From ed26fe226b23a14b3371c4d8206bed182bbbe65d Mon Sep 17 00:00:00 2001 From: Eike Kettner Date: Tue, 10 Nov 2020 22:25:25 +0100 Subject: [PATCH 1/3] Split item card it several functions --- modules/webapp/src/main/elm/Comp/ItemCard.elm | 506 ++++++++++-------- 1 file changed, 272 insertions(+), 234 deletions(-) diff --git a/modules/webapp/src/main/elm/Comp/ItemCard.elm b/modules/webapp/src/main/elm/Comp/ItemCard.elm index 95e758cc..a1e00fbd 100644 --- a/modules/webapp/src/main/elm/Comp/ItemCard.elm +++ b/modules/webapp/src/main/elm/Comp/ItemCard.elm @@ -4,6 +4,7 @@ import Api import Api.Model.AttachmentLight exposing (AttachmentLight) import Api.Model.HighlightEntry exposing (HighlightEntry) import Api.Model.ItemLight exposing (ItemLight) +import Data.BasicSize import Data.Direction import Data.Fields import Data.Icons as Icons @@ -117,29 +118,6 @@ update ddm msg model = view : ViewConfig -> UiSettings -> Model -> ItemLight -> Html Msg view cfg settings model item = let - dirIcon = - i [ class (Data.Direction.iconFromMaybe item.direction) ] [] - - corr = - List.filterMap identity [ item.corrOrg, item.corrPerson ] - |> List.map .name - |> List.intersperse ", " - |> String.concat - - conc = - List.filterMap identity [ item.concPerson, item.concEquip ] - |> List.map .name - |> List.intersperse ", " - |> String.concat - - folder = - Maybe.map .name item.folder - |> Maybe.withDefault "" - - dueDate = - Maybe.map Util.Time.formatDateShort item.dueDate - |> Maybe.withDefault "" - isConfirmed = item.state /= "created" @@ -163,55 +141,6 @@ view cfg settings model item = Data.ItemSelection.Active ids -> onClick (ToggleSelectItem ids item.id) - - mainAttach = - currentAttachment model item - - previewUrl = - Maybe.map .id mainAttach - |> Maybe.map Api.attachmentPreviewURL - |> Maybe.withDefault (Api.itemBasePreviewURL item.id) - - pageCount = - Maybe.andThen .pageCount mainAttach - |> Maybe.withDefault 0 - - pageCountLabel = - div - [ classList - [ ( "card-attachment-nav top", True ) - , ( "invisible", pageCount == 0 || (item.fileCount == 1 && pageCount == 1) ) - ] - ] - [ if item.fileCount == 1 then - div - [ class "ui secondary basic mini label" - , title "Number of pages" - ] - [ text "p." - , text (String.fromInt pageCount) - ] - - else - div [ class "ui left labeled mini button" ] - [ div [ class "ui basic right pointing mini label" ] - [ currentPosition model item - |> String.fromInt - |> text - , text "/" - , text (String.fromInt item.fileCount) - , text " p." - , text (String.fromInt pageCount) - ] - , a - [ class "ui mini icon secondary button" - , href "#" - , onClick (CyclePreview item) - ] - [ i [ class "arrow right icon" ] [] - ] - ] - ] in div ([ classList @@ -227,183 +156,292 @@ view cfg settings model item = span [ class "invisible" ] [] else - div - [ class "image ds-card-image" - , Data.UiSettings.cardPreviewSize settings - ] - [ img - [ class "preview-image" - , src previewUrl - , Data.UiSettings.cardPreviewSize settings - ] - [] - , pageCountLabel - ] - , a - [ class "link content" - , href "#" - , cardAction + previewImage settings model item + , mainContent cardAction cardColor isConfirmed settings cfg item + , notesContent settings item + , metaDataContent settings item + , fulltextResultsContent item + ] + + +fulltextResultsContent : ItemLight -> Html Msg +fulltextResultsContent item = + div + [ classList + [ ( "content search-highlight", True ) + , ( "invisible hidden", item.highlighting == [] ) ] - [ case cfg.selection of - Data.ItemSelection.Active ids -> + ] + [ div [ class "ui list" ] + (List.map renderHighlightEntry item.highlighting) + ] + + +metaDataContent : UiSettings -> ItemLight -> Html Msg +metaDataContent settings item = + let + fieldHidden f = + Data.UiSettings.fieldHidden settings f + + corr = + List.filterMap identity [ item.corrOrg, item.corrPerson ] + |> List.map .name + |> List.intersperse ", " + |> String.concat + + conc = + List.filterMap identity [ item.concPerson, item.concEquip ] + |> List.map .name + |> List.intersperse ", " + |> String.concat + + folder = + Maybe.map .name item.folder + |> Maybe.withDefault "" + + dueDate = + Maybe.map Util.Time.formatDateShort item.dueDate + |> Maybe.withDefault "" + in + div [ class "content" ] + [ div [ class "ui horizontal list" ] + [ div + [ classList + [ ( "item", True ) + , ( "invisible hidden" + , fieldHidden Data.Fields.CorrOrg + && fieldHidden Data.Fields.CorrPerson + ) + ] + , title "Correspondent" + ] + [ Icons.correspondentIcon "" + , text " " + , Util.String.withDefault "-" corr |> text + ] + , div + [ classList + [ ( "item", True ) + , ( "invisible hidden" + , fieldHidden Data.Fields.ConcPerson + && fieldHidden Data.Fields.ConcEquip + ) + ] + , title "Concerning" + ] + [ Icons.concernedIcon + , text " " + , Util.String.withDefault "-" conc |> text + ] + , div + [ classList + [ ( "item", True ) + , ( "invisible hidden", fieldHidden Data.Fields.Folder ) + ] + , title "Folder" + ] + [ Icons.folderIcon "" + , text " " + , Util.String.withDefault "-" folder |> text + ] + ] + , div [ class "right floated meta" ] + [ div [ class "ui horizontal list" ] + [ div + [ class "item" + , title "Source" + ] + [ text item.source + ] + , div + [ classList + [ ( "item", True ) + , ( "invisible hidden" + , item.dueDate + == Nothing + || fieldHidden Data.Fields.DueDate + ) + ] + , title ("Due on " ++ dueDate) + ] + [ div + [ class "ui basic grey label" + ] + [ Icons.dueDateIcon "" + , text (" " ++ dueDate) + ] + ] + ] + ] + ] + + +notesContent : UiSettings -> ItemLight -> Html Msg +notesContent settings item = + div + [ classList + [ ( "content", True ) + , ( "invisible hidden" + , settings.itemSearchNoteLength + <= 0 + || Util.String.isNothingOrBlank item.notes + ) + ] + ] + [ span [ class "small-info" ] + [ Maybe.withDefault "" item.notes + |> Util.String.ellipsis settings.itemSearchNoteLength + |> text + ] + ] + + +mainContent : Attribute Msg -> String -> Bool -> UiSettings -> ViewConfig -> ItemLight -> Html Msg +mainContent cardAction cardColor isConfirmed settings cfg item = + let + dirIcon = + i [ class (Data.Direction.iconFromMaybe item.direction) ] [] + + fieldHidden f = + Data.UiSettings.fieldHidden settings f + in + a + [ class "link content" + , href "#" + , cardAction + ] + [ case cfg.selection of + Data.ItemSelection.Active ids -> + div [ class "header" ] + [ Util.Html.checkbox (Set.member item.id ids) + , dirIcon + , Util.String.underscoreToSpace item.name + |> text + ] + + Data.ItemSelection.Inactive -> + if fieldHidden Data.Fields.Direction then div [ class "header" ] - [ Util.Html.checkbox (Set.member item.id ids) - , dirIcon + [ Util.String.underscoreToSpace item.name |> text + ] + + else + div + [ class "header" + , Data.Direction.labelFromMaybe item.direction + |> title + ] + [ dirIcon , Util.String.underscoreToSpace item.name |> text ] - - Data.ItemSelection.Inactive -> - if fieldHidden Data.Fields.Direction then - div [ class "header" ] - [ Util.String.underscoreToSpace item.name |> text - ] - - else + , div + [ classList + [ ( "ui right corner label", True ) + , ( cardColor, True ) + , ( "invisible", isConfirmed ) + ] + , title "New" + ] + [ i [ class "exclamation icon" ] [] + ] + , div + [ classList + [ ( "meta", True ) + , ( "invisible hidden", fieldHidden Data.Fields.Date ) + ] + ] + [ Util.Time.formatDate item.date |> text + ] + , div [ class "meta description" ] + [ div + [ classList + [ ( "ui right floated tiny labels", True ) + , ( "invisible hidden", item.tags == [] || fieldHidden Data.Fields.Tag ) + ] + ] + (List.map + (\tag -> div - [ class "header" - , Data.Direction.labelFromMaybe item.direction - |> title - ] - [ dirIcon - , Util.String.underscoreToSpace item.name - |> text - ] - , div - [ classList - [ ( "ui right corner label", True ) - , ( cardColor, True ) - , ( "invisible", isConfirmed ) - ] - , title "New" - ] - [ i [ class "exclamation icon" ] [] - ] - , div - [ classList - [ ( "meta", True ) - , ( "invisible hidden", fieldHidden Data.Fields.Date ) - ] - ] - [ Util.Time.formatDate item.date |> text - ] - , div [ class "meta description" ] - [ div - [ classList - [ ( "ui right floated tiny labels", True ) - , ( "invisible hidden", item.tags == [] || fieldHidden Data.Fields.Tag ) - ] - ] - (List.map - (\tag -> - div - [ classList - [ ( "ui basic label", True ) - , ( Data.UiSettings.tagColorString tag settings, True ) - ] + [ classList + [ ( "ui basic label", True ) + , ( Data.UiSettings.tagColorString tag settings, True ) ] - [ text tag.name ] - ) - item.tags + ] + [ text tag.name ] ) - ] + item.tags + ) ] - , div - [ classList - [ ( "content", True ) - , ( "invisible hidden" - , settings.itemSearchNoteLength - <= 0 - || Util.String.isNothingOrBlank item.notes - ) - ] + ] + + +previewImage : UiSettings -> Model -> ItemLight -> Html Msg +previewImage settings model item = + let + previewUrl = + Maybe.map .id mainAttach + |> Maybe.map Api.attachmentPreviewURL + |> Maybe.withDefault (Api.itemBasePreviewURL item.id) + + mainAttach = + currentAttachment model item + in + div + [ class "image ds-card-image" + , Data.UiSettings.cardPreviewSize settings + ] + [ img + [ class "preview-image" + , src previewUrl + , Data.UiSettings.cardPreviewSize settings ] - [ span [ class "small-info" ] - [ Maybe.withDefault "" item.notes - |> Util.String.ellipsis settings.itemSearchNoteLength - |> text - ] + [] + , pageCountLabel model item mainAttach + ] + + +pageCountLabel : Model -> ItemLight -> Maybe AttachmentLight -> Html Msg +pageCountLabel model item mainAttach = + let + pageCount = + Maybe.andThen .pageCount mainAttach + |> Maybe.withDefault 0 + in + div + [ classList + [ ( "card-attachment-nav top", True ) + , ( "invisible", pageCount == 0 || (item.fileCount == 1 && pageCount == 1) ) ] - , div [ class "content" ] - [ div [ class "ui horizontal list" ] - [ div - [ classList - [ ( "item", True ) - , ( "invisible hidden" - , fieldHidden Data.Fields.CorrOrg - && fieldHidden Data.Fields.CorrPerson - ) - ] - , title "Correspondent" + ] + [ if item.fileCount == 1 then + div + [ class "ui secondary basic mini label" + , title "Number of pages" + ] + [ text "p." + , text (String.fromInt pageCount) + ] + + else + div [ class "ui left labeled mini button" ] + [ div [ class "ui basic right pointing mini label" ] + [ currentPosition model item + |> String.fromInt + |> text + , text "/" + , text (String.fromInt item.fileCount) + , text " p." + , text (String.fromInt pageCount) ] - [ Icons.correspondentIcon "" - , text " " - , Util.String.withDefault "-" corr |> text + , a + [ class "ui mini icon secondary button" + , href "#" + , onClick (CyclePreview item) ] - , div - [ classList - [ ( "item", True ) - , ( "invisible hidden" - , fieldHidden Data.Fields.ConcPerson - && fieldHidden Data.Fields.ConcEquip - ) - ] - , title "Concerning" - ] - [ Icons.concernedIcon - , text " " - , Util.String.withDefault "-" conc |> text - ] - , div - [ classList - [ ( "item", True ) - , ( "invisible hidden", fieldHidden Data.Fields.Folder ) - ] - , title "Folder" - ] - [ Icons.folderIcon "" - , text " " - , Util.String.withDefault "-" folder |> text + [ i [ class "arrow right icon" ] [] ] ] - , div [ class "right floated meta" ] - [ div [ class "ui horizontal list" ] - [ div - [ class "item" - , title "Source" - ] - [ text item.source - ] - , div - [ classList - [ ( "item", True ) - , ( "invisible hidden" - , item.dueDate - == Nothing - || fieldHidden Data.Fields.DueDate - ) - ] - , title ("Due on " ++ dueDate) - ] - [ div - [ class "ui basic grey label" - ] - [ Icons.dueDateIcon "" - , text (" " ++ dueDate) - ] - ] - ] - ] - ] - , div - [ classList - [ ( "content search-highlight", True ) - , ( "invisible hidden", item.highlighting == [] ) - ] - ] - [ div [ class "ui list" ] - (List.map renderHighlightEntry item.highlighting) - ] ] From 746e04c6241a187eeadd0adb90172f6c614ec963 Mon Sep 17 00:00:00 2001 From: Eike Kettner Date: Tue, 10 Nov 2020 22:25:46 +0100 Subject: [PATCH 2/3] Improve logging when creating preview images --- .../docspell/joex/preview/MakePreviewTask.scala | 2 +- .../docspell/joex/process/AttachmentPreview.scala | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/joex/src/main/scala/docspell/joex/preview/MakePreviewTask.scala b/modules/joex/src/main/scala/docspell/joex/preview/MakePreviewTask.scala index ba9671f5..6e626b17 100644 --- a/modules/joex/src/main/scala/docspell/joex/preview/MakePreviewTask.scala +++ b/modules/joex/src/main/scala/docspell/joex/preview/MakePreviewTask.scala @@ -47,7 +47,7 @@ object MakePreviewTask { _ <- ra .map(AttachmentPreview.createPreview(ctx, preview, cfg.chunkSize)) .getOrElse( - ctx.logger.warn(s"No attachment found with id: ${ctx.args.attachment}") + ctx.logger.error(s"No attachment found with id: ${ctx.args.attachment}") ) } yield () diff --git a/modules/joex/src/main/scala/docspell/joex/process/AttachmentPreview.scala b/modules/joex/src/main/scala/docspell/joex/process/AttachmentPreview.scala index e42e67ab..57a0c170 100644 --- a/modules/joex/src/main/scala/docspell/joex/process/AttachmentPreview.scala +++ b/modules/joex/src/main/scala/docspell/joex/process/AttachmentPreview.scala @@ -57,13 +57,17 @@ object AttachmentPreview { case MimeType.PdfMatch(_) => preview.previewPNG(loadFile(ctx)(ra)).flatMap { case Some(out) => - createRecord(ctx, out, ra, chunkSize).map(_.some) + ctx.logger.debug("Preview generated, saving to database…") *> + createRecord(ctx, out, ra, chunkSize).map(_.some) case None => - (None: Option[RAttachmentPreview]).pure[F] + ctx.logger + .info(s"Preview could not be generated. Maybe the pdf has no pages?") *> + (None: Option[RAttachmentPreview]).pure[F] } - case _ => - (None: Option[RAttachmentPreview]).pure[F] + case mt => + ctx.logger.warn(s"Not a pdf file, but ${mt.asString}, cannot get page count.") *> + (None: Option[RAttachmentPreview]).pure[F] } private def createRecord[F[_]: Sync]( From cd81161cb020d4556f0b1c54d2b45a9d8feb7ace Mon Sep 17 00:00:00 2001 From: Eike Kettner Date: Tue, 10 Nov 2020 22:28:34 +0100 Subject: [PATCH 3/3] Add support for jbig2 encoded images This is often used for binary images. Closes: #433 --- project/Dependencies.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 115f3c79..a3a96d65 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -21,6 +21,7 @@ object Dependencies { val Icu4jVersion = "68.1" val JsoupVersion = "1.13.1" val KindProjectorVersion = "0.10.3" + val LevigoJbig2Version = "2.0" val Log4sVersion = "1.9.0" val LogbackVersion = "1.2.3" val MariaDbVersion = "2.7.0" @@ -85,12 +86,16 @@ object Dependencies { "com.twelvemonkeys.imageio" % "imageio-tiff" % TwelveMonkeysVersion ) + val levigoJbig2 = Seq( + "com.levigo.jbig2" % "levigo-jbig2-imageio" % LevigoJbig2Version + ) + val pdfbox = Seq( ("org.apache.pdfbox" % "pdfbox" % PdfboxVersion).excludeAll( ExclusionRule("org.bouncycastle"), ExclusionRule("commons-logging") ) - ) ++ jclOverSlf4j + ) ++ jclOverSlf4j ++ levigoJbig2 val emilCommon = Seq( "com.github.eikek" %% "emil-common" % EmilVersion