mirror of
				https://github.com/TheAnachronism/docspell.git
				synced 2025-10-31 09:30:12 +00:00 
			
		
		
		
	Minor improvements
- use a one-line log format - load templates only once - fixed typos - fix reset timezone in ui settings - hide bookmarks headline if there are none
This commit is contained in:
		| @@ -47,7 +47,7 @@ object ScribeConfigure { | ||||
|         if (logger.id == scribe.Logger.RootId) { | ||||
|           cfg.format match { | ||||
|             case Format.Fancy => | ||||
|               l.withHandler(formatter = Formatter.default, writer = SystemOutWriter) | ||||
|               l.withHandler(formatter = Formatter.enhanced, writer = SystemOutWriter) | ||||
|             case Format.Plain => | ||||
|               l.withHandler(formatter = Formatter.classic, writer = SystemOutWriter) | ||||
|             case Format.Json => | ||||
|   | ||||
| @@ -104,7 +104,7 @@ object RestServer { | ||||
|   )( | ||||
|       wsB: WebSocketBuilder2[F] | ||||
|   ) = { | ||||
|     val templates = TemplateRoutes[F](cfg) | ||||
|     val templates = TemplateRoutes[F](cfg, Templates[F]) | ||||
|     val httpApp = Router( | ||||
|       "/internal" -> InternalHeader(internSettings.internalRouteKey) { | ||||
|         internalRoutes(pubSub) | ||||
|   | ||||
| @@ -6,12 +6,8 @@ | ||||
|  | ||||
| package docspell.restserver.webapp | ||||
|  | ||||
| import java.net.URL | ||||
| import java.util.concurrent.atomic.AtomicReference | ||||
|  | ||||
| import cats.effect._ | ||||
| import cats.implicits._ | ||||
| import fs2.text | ||||
|  | ||||
| import docspell.restserver.{BuildInfo, Config} | ||||
|  | ||||
| @@ -36,22 +32,16 @@ object TemplateRoutes { | ||||
|     def serviceWorker: HttpRoutes[F] | ||||
|   } | ||||
|  | ||||
|   def apply[F[_]: Async](cfg: Config): InnerRoutes[F] = { | ||||
|     val indexTemplate = memo( | ||||
|       loadResource("/index.html").flatMap(loadTemplate(_)) | ||||
|     ) | ||||
|     val docTemplate = memo(loadResource("/doc.html").flatMap(loadTemplate(_))) | ||||
|     val swTemplate = memo(loadResource("/sw.js").flatMap(loadTemplate(_))) | ||||
|  | ||||
|   def apply[F[_]: Async](cfg: Config, templates: Templates[F]): InnerRoutes[F] = { | ||||
|     val dsl = new Http4sDsl[F] {} | ||||
|     import dsl._ | ||||
|     new InnerRoutes[F] { | ||||
|       def doc = | ||||
|         HttpRoutes.of[F] { case GET -> Root => | ||||
|           for { | ||||
|             templ <- docTemplate | ||||
|             docTemplate <- templates.doc | ||||
|             resp <- Ok( | ||||
|               DocData().render(templ), | ||||
|               DocData().render(docTemplate), | ||||
|               `Content-Type`(textHtml, Charset.`UTF-8`) | ||||
|             ) | ||||
|           } yield resp | ||||
| @@ -59,9 +49,9 @@ object TemplateRoutes { | ||||
|       def app = | ||||
|         HttpRoutes.of[F] { case GET -> _ => | ||||
|           for { | ||||
|             templ <- indexTemplate | ||||
|             indexTemplate <- templates.index | ||||
|             resp <- Ok( | ||||
|               IndexData(cfg).render(templ), | ||||
|               IndexData(cfg).render(indexTemplate), | ||||
|               `Content-Type`(textHtml, Charset.`UTF-8`) | ||||
|             ) | ||||
|           } yield resp | ||||
| @@ -70,9 +60,9 @@ object TemplateRoutes { | ||||
|       def serviceWorker = | ||||
|         HttpRoutes.of[F] { case GET -> _ => | ||||
|           for { | ||||
|             templ <- swTemplate | ||||
|             swTemplate <- templates.serviceWorker | ||||
|             resp <- Ok( | ||||
|               IndexData(cfg).render(templ), | ||||
|               IndexData(cfg).render(swTemplate), | ||||
|               `Content-Type`(appJavascript, Charset.`UTF-8`) | ||||
|             ) | ||||
|           } yield resp | ||||
| @@ -80,31 +70,6 @@ object TemplateRoutes { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   def loadResource[F[_]: Sync](name: String): F[URL] = | ||||
|     Option(getClass.getResource(name)) match { | ||||
|       case None => | ||||
|         Sync[F].raiseError(new Exception("Unknown resource: " + name)) | ||||
|       case Some(r) => | ||||
|         r.pure[F] | ||||
|     } | ||||
|  | ||||
|   def loadUrl[F[_]: Sync](url: URL): F[String] = | ||||
|     fs2.io | ||||
|       .readInputStream(Sync[F].delay(url.openStream()), 64 * 1024) | ||||
|       .through(text.utf8.decode) | ||||
|       .compile | ||||
|       .string | ||||
|  | ||||
|   def parseTemplate[F[_]: Sync](str: String): F[Template] = | ||||
|     Sync[F].pure(mustache.parse(str).leftMap(err => new Exception(err._2))).rethrow | ||||
|  | ||||
|   def loadTemplate[F[_]: Sync](url: URL): F[Template] = { | ||||
|     val logger = docspell.logging.getLogger[F] | ||||
|     loadUrl[F](url).flatMap(parseTemplate[F]).flatMap { t => | ||||
|       logger.info(s"Compiled template $url") *> t.pure[F] | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   case class DocData(swaggerRoot: String, openapiSpec: String) | ||||
|   object DocData { | ||||
|  | ||||
| @@ -150,18 +115,4 @@ object TemplateRoutes { | ||||
|     implicit def yamuscaValueConverter: ValueConverter[IndexData] = | ||||
|       deriveValueConverter[IndexData] | ||||
|   } | ||||
|  | ||||
|   private def memo[F[_]: Sync, A](fa: => F[A]): F[A] = { | ||||
|     val ref = new AtomicReference[A]() | ||||
|     Sync[F].defer { | ||||
|       Option(ref.get) match { | ||||
|         case Some(a) => a.pure[F] | ||||
|         case None => | ||||
|           fa.map { a => | ||||
|             ref.set(a) | ||||
|             a | ||||
|           } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,64 @@ | ||||
| /* | ||||
|  * Copyright 2020 Eike K. & Contributors | ||||
|  * | ||||
|  * SPDX-License-Identifier: AGPL-3.0-or-later | ||||
|  */ | ||||
|  | ||||
| package docspell.restserver.webapp | ||||
|  | ||||
| import java.net.URL | ||||
|  | ||||
| import cats.effect._ | ||||
| import cats.effect.unsafe.implicits._ | ||||
| import cats.implicits._ | ||||
| import fs2.text | ||||
|  | ||||
| import yamusca.imports._ | ||||
|  | ||||
| trait Templates[F[_]] { | ||||
|   def index: F[Template] | ||||
|   def doc: F[Template] | ||||
|   def serviceWorker: F[Template] | ||||
| } | ||||
|  | ||||
| object Templates { | ||||
|  | ||||
|   def apply[F[_]: Sync]: Templates[F] = | ||||
|     new Templates[F] { | ||||
|       def index = Templates.indexTemplate.pure[F] | ||||
|       def doc = Templates.docTemplate.pure[F] | ||||
|       def serviceWorker = Templates.swTemplate.pure[F] | ||||
|     } | ||||
|  | ||||
|   private lazy val indexTemplate = fromResource[IO]("/index.html").unsafeRunSync() | ||||
|   private lazy val docTemplate = fromResource[IO]("/doc.html").unsafeRunSync() | ||||
|   private lazy val swTemplate = fromResource[IO]("/sw.js").unsafeRunSync() | ||||
|  | ||||
|   def fromResource[F[_]: Sync](path: String): F[Template] = | ||||
|     loadResource[F](path).flatMap(loadTemplate[F](_)) | ||||
|  | ||||
|   private def loadResource[F[_]: Sync](name: String): F[URL] = | ||||
|     Option(getClass.getResource(name)) match { | ||||
|       case None => | ||||
|         Sync[F].raiseError(new Exception("Unknown resource: " + name)) | ||||
|       case Some(r) => | ||||
|         r.pure[F] | ||||
|     } | ||||
|  | ||||
|   private def loadUrl[F[_]: Sync](url: URL): F[String] = | ||||
|     fs2.io | ||||
|       .readInputStream(Sync[F].delay(url.openStream()), 64 * 1024) | ||||
|       .through(text.utf8.decode) | ||||
|       .compile | ||||
|       .string | ||||
|  | ||||
|   private def parseTemplate[F[_]: Sync](str: String): F[Template] = | ||||
|     Sync[F].pure(mustache.parse(str).leftMap(err => new Exception(err._2))).rethrow | ||||
|  | ||||
|   private def loadTemplate[F[_]: Sync](url: URL): F[Template] = { | ||||
|     val logger = docspell.logging.getLogger[F] | ||||
|     loadUrl[F](url).flatMap(parseTemplate[F]).flatMap { t => | ||||
|       logger.info(s"Compiled template $url") *> t.pure[F] | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -308,7 +308,7 @@ view texts settings model = | ||||
|                 (Comp.EventSample.viewJson texts.eventSample False model.eventSampleModel) | ||||
|             ] | ||||
|         , div [ class "mt-4" ] | ||||
|             [ formHeader "Test Delviery" | ||||
|             [ formHeader "Test Delivery" | ||||
|             , Html.map DeliveryTestMsg | ||||
|                 (Comp.NotificationTest.view | ||||
|                     { runDisabled = getHook model == Nothing } | ||||
|   | ||||
| @@ -569,7 +569,7 @@ update flags sett msg model = | ||||
|                 newSettings = | ||||
|                     case tab of | ||||
|                         GeneralTab -> | ||||
|                             { sett | uiLang = Nothing, sideMenuVisible = Nothing } | ||||
|                             { sett | uiLang = Nothing, timeZone = Nothing, sideMenuVisible = Nothing } | ||||
|  | ||||
|                         SearchTab -> | ||||
|                             { sett | ||||
|   | ||||
| @@ -31,20 +31,22 @@ view texts versionInfo _ model = | ||||
|             , menuLink [ Page.href (SearchPage Nothing) ] (Icons.searchIcon "") texts.basics.items | ||||
|             , menuLink [ onClick InitUpload, href "#" ] (Icons.fileUploadIcon "") texts.uploadFiles | ||||
|             ] | ||||
|         , h3 | ||||
|             [ class S.header3 | ||||
|             , class "italic mt-3" | ||||
|             ] | ||||
|             [ text texts.bookmarks | ||||
|             ] | ||||
|         , div [ class "ml-2" ] | ||||
|             [ Html.map BookmarkMsg | ||||
|                 (Comp.BookmarkChooser.viewWith | ||||
|                     { showUser = True, showCollective = True, showShares = False } | ||||
|                     texts.bookmarkChooser | ||||
|                     model.sideMenu.bookmarkChooser | ||||
|                     Comp.BookmarkChooser.emptySelection | ||||
|                 ) | ||||
|         , div [ classList [ ( "hidden", Comp.BookmarkChooser.isEmpty model.sideMenu.bookmarkChooser ) ] ] | ||||
|             [ h3 | ||||
|                 [ class S.header3 | ||||
|                 , class "italic mt-3" | ||||
|                 ] | ||||
|                 [ text texts.bookmarks | ||||
|                 ] | ||||
|             , div [ class "ml-2" ] | ||||
|                 [ Html.map BookmarkMsg | ||||
|                     (Comp.BookmarkChooser.viewWith | ||||
|                         { showUser = True, showCollective = True, showShares = False } | ||||
|                         texts.bookmarkChooser | ||||
|                         model.sideMenu.bookmarkChooser | ||||
|                         Comp.BookmarkChooser.emptySelection | ||||
|                     ) | ||||
|                 ] | ||||
|             ] | ||||
|         , h3 | ||||
|             [ class S.header3 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user