Merge pull request #707 from eikek/reprocess

Reprocess
This commit is contained in:
mergify[bot] 2021-03-12 00:05:30 +00:00 committed by GitHub
commit cacad17df6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 448 additions and 108 deletions

View File

@ -145,7 +145,8 @@ object OUpload {
data.meta.validFileTypes,
data.meta.skipDuplicates,
data.meta.fileFilter.some,
data.meta.tags.some
data.meta.tags.some,
false
)
args =
if (data.multiple) files.map(f => ProcessItemArgs(meta, List(f)))

View File

@ -13,6 +13,8 @@ import io.circe.generic.semiauto._
*
* If the `itemId' is set to some value, the item is tried to load to
* ammend with the given files. Otherwise a new item is created.
*
* It is also re-used by the 'ReProcessItem' task.
*/
case class ProcessItemArgs(meta: ProcessMeta, files: List[File]) {
@ -24,6 +26,8 @@ case class ProcessItemArgs(meta: ProcessMeta, files: List[File]) {
case _ => s"${files.size} files from ${meta.sourceAbbrev}"
}
def isNormalProcessing: Boolean =
!meta.reprocess
}
object ProcessItemArgs {
@ -40,7 +44,8 @@ object ProcessItemArgs {
validFileTypes: Seq[MimeType],
skipDuplicate: Boolean,
fileFilter: Option[Glob],
tags: Option[List[String]]
tags: Option[List[String]],
reprocess: Boolean
)
object ProcessMeta {

View File

@ -113,7 +113,7 @@ object JoexAppImpl {
.withTask(
JobTask.json(
ReProcessItemArgs.taskName,
ReProcessItem[F](cfg, fts, analyser, regexNer),
ReProcessItem[F](cfg, fts, itemOps, analyser, regexNer),
ReProcessItem.onCancel[F]
)
)

View File

@ -40,14 +40,14 @@ object ConvertPdf {
Task { ctx =>
def convert(ra: RAttachment): F[(RAttachment, Option[RAttachmentMeta])] =
isConverted(ctx)(ra).flatMap {
case true =>
case true if ctx.args.isNormalProcessing =>
ctx.logger.info(
s"Conversion to pdf already done for attachment ${ra.name}."
) *>
ctx.store
.transact(RAttachmentMeta.findById(ra.id))
.map(rmOpt => (ra, rmOpt))
case false =>
case _ =>
findMime(ctx)(ra).flatMap(m =>
convertSafe(cfg, JsoupSanitizer.clean, ctx, item)(ra, m)
)

View File

@ -10,11 +10,19 @@ import docspell.store.records.RItem
object LinkProposal {
def apply[F[_]: Sync](data: ItemData): Task[F, ProcessItemArgs, ItemData] =
def onlyNew[F[_]: Sync](data: ItemData): Task[F, ProcessItemArgs, ItemData] =
if (data.item.state.isValid)
Task
.log[F, ProcessItemArgs](_.debug(s"Not linking proposals on existing item"))
.map(_ => data)
else
LinkProposal[F](data)
def apply[F[_]: Sync](data: ItemData): Task[F, ProcessItemArgs, ItemData] =
if (data.item.state == ItemState.Confirmed)
Task
.log[F, ProcessItemArgs](_.debug(s"Not linking proposals on confirmed item"))
.map(_ => data)
else
Task { ctx =>
val proposals = data.finalProposals

View File

@ -22,8 +22,8 @@ object ProcessItem {
ExtractArchive(item)
.flatMap(Task.setProgress(20))
.flatMap(processAttachments0(cfg, fts, analyser, regexNer, (40, 60, 80)))
.flatMap(LinkProposal[F])
.flatMap(SetGivenData[F](itemOps))
.flatMap(LinkProposal.onlyNew[F])
.flatMap(SetGivenData.onlyNew[F](itemOps))
.flatMap(Task.setProgress(99))
.flatMap(RemoveEmptyItem(itemOps))

View File

@ -5,6 +5,7 @@ import cats.effect._
import cats.implicits._
import docspell.analysis.TextAnalyser
import docspell.backend.ops.OItem
import docspell.common._
import docspell.ftsclient.FtsClient
import docspell.joex.Config
@ -22,12 +23,17 @@ object ReProcessItem {
def apply[F[_]: ConcurrentEffect: ContextShift](
cfg: Config,
fts: FtsClient[F],
itemOps: OItem[F],
analyser: TextAnalyser[F],
regexNer: RegexNerFile[F]
): Task[F, Args, Unit] =
Task
.log[F, Args](_.info("===== Start reprocessing ======"))
.flatMap(_ =>
loadItem[F]
.flatMap(safeProcess[F](cfg, fts, analyser, regexNer))
.flatMap(safeProcess[F](cfg, fts, itemOps, analyser, regexNer))
.map(_ => ())
)
def onCancel[F[_]]: Task[F, Args, Unit] =
logWarn("Now cancelling re-processing.")
@ -58,6 +64,11 @@ object ReProcessItem {
a.copy(fileId = src.fileId, name = src.name)
}
)
_ <- OptionT.liftF(
ctx.logger.debug(
s"Loaded item and ${attachSrc.size} attachments to reprocess"
)
)
} yield ItemData(
item,
attachSrc,
@ -76,6 +87,7 @@ object ReProcessItem {
def processFiles[F[_]: ConcurrentEffect: ContextShift](
cfg: Config,
fts: FtsClient[F],
itemOps: OItem[F],
analyser: TextAnalyser[F],
regexNer: RegexNerFile[F],
data: ItemData
@ -90,12 +102,13 @@ object ReProcessItem {
args.itemId.some,
lang,
None, //direction
"", //source-id
data.item.source, //source-id
None, //folder
Seq.empty,
false,
None,
None
None,
true
),
Nil
).pure[F]
@ -103,6 +116,8 @@ object ReProcessItem {
getLanguage[F].flatMap { lang =>
ProcessItem
.processAttachments[F](cfg, fts, analyser, regexNer)(data)
.flatMap(LinkProposal[F])
.flatMap(SetGivenData[F](itemOps))
.contramap[Args](convertArgs(lang))
}
}
@ -121,12 +136,13 @@ object ReProcessItem {
def safeProcess[F[_]: ConcurrentEffect: ContextShift](
cfg: Config,
fts: FtsClient[F],
itemOps: OItem[F],
analyser: TextAnalyser[F],
regexNer: RegexNerFile[F]
)(data: ItemData): Task[F, Args, ItemData] =
isLastRetry[F].flatMap {
case true =>
processFiles[F](cfg, fts, analyser, regexNer, data).attempt
processFiles[F](cfg, fts, itemOps, analyser, regexNer, data).attempt
.flatMap({
case Right(d) =>
Task.pure(d)
@ -136,7 +152,7 @@ object ReProcessItem {
).andThen(_ => Sync[F].raiseError(ex))
})
case false =>
processFiles[F](cfg, fts, analyser, regexNer, data)
processFiles[F](cfg, fts, itemOps, analyser, regexNer, data)
}
private def logWarn[F[_]](msg: => String): Task[F, Args, Unit] =

View File

@ -8,13 +8,20 @@ import docspell.common._
import docspell.joex.scheduler.Task
object SetGivenData {
type Args = ProcessItemArgs
def apply[F[_]: Sync](
ops: OItem[F]
)(data: ItemData): Task[F, ProcessItemArgs, ItemData] =
def onlyNew[F[_]: Sync](ops: OItem[F])(data: ItemData): Task[F, Args, ItemData] =
if (data.item.state.isValid)
Task
.log[F, ProcessItemArgs](_.debug(s"Not setting data on existing item"))
.log[F, Args](_.debug(s"Not setting data on existing item"))
.map(_ => data)
else
SetGivenData[F](ops)(data)
def apply[F[_]: Sync](ops: OItem[F])(data: ItemData): Task[F, Args, ItemData] =
if (data.item.state == ItemState.Confirmed)
Task
.log[F, Args](_.debug(s"Not setting data on confirmed item"))
.map(_ => data)
else
setFolder(data, ops).flatMap(d => setTags[F](d, ops))
@ -22,7 +29,7 @@ object SetGivenData {
private def setFolder[F[_]: Sync](
data: ItemData,
ops: OItem[F]
): Task[F, ProcessItemArgs, ItemData] =
): Task[F, Args, ItemData] =
Task { ctx =>
val itemId = data.item.id
val folderId = ctx.args.meta.folderId
@ -41,7 +48,7 @@ object SetGivenData {
private def setTags[F[_]: Sync](
data: ItemData,
ops: OItem[F]
): Task[F, ProcessItemArgs, ItemData] =
): Task[F, Args, ItemData] =
Task { ctx =>
val itemId = data.item.id
val collective = ctx.args.meta.collective

View File

@ -84,10 +84,10 @@ object TextExtraction {
val rm = item.findOrCreate(ra.id, lang)
rm.content match {
case Some(_) =>
case Some(_) if ctx.args.isNormalProcessing =>
ctx.logger.info("TextExtraction skipped, since text is already available.") *>
makeTextData((rm, Nil)).pure[F]
case None =>
case _ =>
extractTextToMeta[F](ctx, cfg, lang, item)(ra)
.map(makeTextData)
}

View File

@ -2113,7 +2113,11 @@ paths:
summary: Start reprocessing the files of the item.
description: |
This submits a job that will re-process the files (either all
or the ones specified) of the item and replace the metadata.
or the ones specified) of the item and replace their metadata.
If the item is not in "confirmed" state, its associated metada
is also updated. Otherwise only the file metadata is updated
(text analysis).
security:
- authTokenHeader: []
parameters:
@ -2515,7 +2519,8 @@ paths:
description: |
Given a list of item-ids, submits all these items for
reprocessing. All attachments of these items will be
reprocessed. Item metadata is not changed.
reprocessed. Item metadata may be changed if an item is not
confirmed. Confirmed items are not changed.
security:
- authTokenHeader: []
requestBody:

View File

@ -89,6 +89,8 @@ module Api exposing
, register
, removeMember
, removeTagsMultiple
, reprocessItem
, reprocessMultiple
, sendMail
, setAttachmentName
, setCollectiveSettings
@ -1423,6 +1425,20 @@ getJobQueueStateTask flags =
--- Item (Mulit Edit)
reprocessMultiple :
Flags
-> Set String
-> (Result Http.Error BasicResult -> msg)
-> Cmd msg
reprocessMultiple flags items receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/items/reprocess"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.IdList.encode (Set.toList items |> IdList))
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
confirmMultiple :
Flags
-> Set String
@ -1637,6 +1653,21 @@ deleteAllItems flags ids receive =
--- Item
reprocessItem :
Flags
-> String
-> List String
-> (Result Http.Error BasicResult -> msg)
-> Cmd msg
reprocessItem flags itemId attachIds receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ itemId ++ "/reprocess"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.IdList.encode (IdList attachIds))
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
attachmentPreviewURL : String -> String
attachmentPreviewURL id =
"/api/v1/sec/attachment/" ++ id ++ "/preview?withFallback=true"

View File

@ -0,0 +1,76 @@
module Comp.ConfirmModal exposing
( Settings
, defaultSettings
, view
)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
import Styles as S
type alias Settings msg =
{ enabled : Bool
, extraClass : String
, headerIcon : String
, headerClass : String
, confirmText : String
, cancelText : String
, message : String
, confirm : msg
, cancel : msg
}
defaultSettings : msg -> msg -> String -> Settings msg
defaultSettings confirm cancel confirmMsg =
{ enabled = True
, extraClass = ""
, headerIcon = "fa fa-exclamation-circle mr-3"
, headerClass = "text-2xl font-bold text-center w-full"
, confirmText = "Ok"
, cancelText = "Cancel"
, message = confirmMsg
, confirm = confirm
, cancel = cancel
}
view : Settings msg -> Html msg
view settings =
div
[ class S.dimmer
, class settings.extraClass
, classList
[ ( "hidden", not settings.enabled )
]
]
[ div [ class settings.headerClass ]
[ i
[ class settings.headerIcon
, class "text-gray-200 font-semibold"
, classList [ ( "hidden", settings.headerClass == "" ) ]
]
[]
, span [ class "text-gray-200 font-semibold" ]
[ text settings.message
]
]
, div [ class "flex flex-row space-x-2 text-xs mt-2" ]
[ a
[ class (S.primaryButton ++ "block font-semibold")
, href "#"
, onClick settings.confirm
]
[ text settings.confirmText
]
, a
[ class (S.secondaryButton ++ "block font-semibold")
, href "#"
, onClick settings.cancel
]
[ text settings.cancelText
]
]
]

View File

@ -28,6 +28,7 @@ import Api.Model.SentMails exposing (SentMails)
import Api.Model.Tag exposing (Tag)
import Api.Model.TagList exposing (TagList)
import Comp.AttachmentMeta
import Comp.ConfirmModal
import Comp.CustomFieldMultiInput
import Comp.DatePicker
import Comp.DetailEdit
@ -72,7 +73,7 @@ type alias Model =
, nameSaveThrottle : Throttle Msg
, notesModel : Maybe String
, notesField : NotesField
, deleteItemConfirm : Comp.YesNoDimmer.Model
, itemModal : Maybe (Comp.ConfirmModal.Settings Msg)
, itemDatePicker : DatePicker
, itemDate : Maybe Int
, itemProposals : ItemProposals
@ -87,7 +88,7 @@ type alias Model =
, attachMeta : Dict String Comp.AttachmentMeta.Model
, attachMetaOpen : Bool
, pdfNativeView : Maybe Bool
, deleteAttachConfirm : Comp.YesNoDimmer.Model
, attachModal : Maybe (Comp.ConfirmModal.Settings Msg)
, addFilesOpen : Bool
, addFilesModel : Comp.Dropzone.Model
, selectedFiles : List File
@ -180,7 +181,7 @@ emptyModel =
, nameSaveThrottle = Throttle.create 1
, notesModel = Nothing
, notesField = ViewNotes
, deleteItemConfirm = Comp.YesNoDimmer.emptyModel
, itemModal = Nothing
, itemDatePicker = Comp.DatePicker.emptyModel
, itemDate = Nothing
, itemProposals = Api.Model.ItemProposals.empty
@ -195,7 +196,7 @@ emptyModel =
, attachMeta = Dict.empty
, attachMetaOpen = False
, pdfNativeView = Nothing
, deleteAttachConfirm = Comp.YesNoDimmer.emptyModel
, attachModal = Nothing
, addFilesOpen = False
, addFilesModel = Comp.Dropzone.init []
, selectedFiles = []
@ -247,7 +248,8 @@ type Msg
| SetDueDateSuggestion Int
| ItemDatePickerMsg Comp.DatePicker.Msg
| DueDatePickerMsg Comp.DatePicker.Msg
| DeleteItemConfirm Comp.YesNoDimmer.Msg
| DeleteItemConfirmed
| ItemModalCancelled
| RequestDelete
| SaveResp (Result Http.Error BasicResult)
| DeleteResp (Result Http.Error BasicResult)
@ -265,7 +267,8 @@ type Msg
| AttachMetaMsg String Comp.AttachmentMeta.Msg
| TogglePdfNativeView Bool
| RequestDeleteAttachment String
| DeleteAttachConfirm String Comp.YesNoDimmer.Msg
| DeleteAttachConfirmed String
| AttachModalCancelled
| DeleteAttachResp (Result Http.Error BasicResult)
| AddFilesToggle
| AddFilesMsg Comp.Dropzone.Msg
@ -304,6 +307,11 @@ type Msg
| ToggleAttachmentDropdown
| ToggleAkkordionTab String
| ToggleOpenAllAkkordionTabs
| RequestReprocessFile String
| ReprocessFileConfirmed String
| ReprocessFileResp (Result Http.Error BasicResult)
| RequestReprocessItem
| ReprocessItemConfirmed
type SaveNameState

View File

@ -3,6 +3,7 @@ module Comp.ItemDetail.SingleAttachment exposing (view)
import Api
import Api.Model.Attachment exposing (Attachment)
import Comp.AttachmentMeta
import Comp.ConfirmModal
import Comp.ItemDetail.Model
exposing
( Model
@ -11,7 +12,6 @@ import Comp.ItemDetail.Model
, SaveNameState(..)
)
import Comp.MenuBar as MB
import Comp.YesNoDimmer
import Data.UiSettings exposing (UiSettings)
import Dict
import Html exposing (..)
@ -37,12 +37,7 @@ view settings model pos attach =
[ ( "hidden", not (attachmentVisible model pos) )
]
]
[ Html.map (DeleteAttachConfirm attach.id)
(Comp.YesNoDimmer.viewN
True
(Comp.YesNoDimmer.defaultSettings2 "Really delete this file?")
model.deleteAttachConfirm
)
[ renderModal model
, div
[ class "flex flex-row px-2 py-2 text-sm"
, class S.border
@ -213,6 +208,13 @@ attachHeader settings model _ attach =
, href "#"
]
}
, { icon = "fa fa-redo-alt"
, label = "Re-process this file"
, attrs =
[ onClick (RequestReprocessFile attach.id)
, href "#"
]
}
, { icon = "fa fa-trash"
, label = "Delete this file"
, attrs =
@ -344,3 +346,13 @@ menuItem model pos attach =
|> text
]
]
renderModal : Model -> Html Msg
renderModal model =
case model.attachModal of
Just confirmModal ->
Comp.ConfirmModal.view confirmModal
Nothing ->
span [ class "hidden" ] []

View File

@ -16,6 +16,7 @@ import Api.Model.ReferenceList exposing (ReferenceList)
import Api.Model.Tag exposing (Tag)
import Browser.Navigation as Nav
import Comp.AttachmentMeta
import Comp.ConfirmModal
import Comp.CustomFieldMultiInput
import Comp.DatePicker
import Comp.DetailEdit
@ -43,7 +44,6 @@ import Comp.MarkdownInput
import Comp.OrgForm
import Comp.PersonForm
import Comp.SentMails
import Comp.YesNoDimmer
import Data.CustomFieldChange exposing (CustomFieldChange(..))
import Data.Direction
import Data.Fields exposing (Field)
@ -532,22 +532,28 @@ update key flags inav settings msg model =
RemoveDueDate ->
resultModelCmd ( { model | dueDate = Nothing }, setDueDate flags model Nothing )
DeleteItemConfirm m ->
DeleteItemConfirmed ->
let
( cm, confirmed ) =
Comp.YesNoDimmer.update m model.deleteItemConfirm
cmd =
if confirmed then
Api.deleteItem flags model.item.id DeleteResp
else
Cmd.none
in
resultModelCmd ( { model | deleteItemConfirm = cm }, cmd )
resultModelCmd ( { model | itemModal = Nothing }, cmd )
ItemModalCancelled ->
resultModel { model | itemModal = Nothing }
RequestDelete ->
update key flags inav settings (DeleteItemConfirm Comp.YesNoDimmer.activate) model
let
confirmMsg =
"Really delete this item? This cannot be undone."
confirm =
Comp.ConfirmModal.defaultSettings
DeleteItemConfirmed
ItemModalCancelled
confirmMsg
in
resultModel { model | itemModal = Just confirm }
SetCorrOrgSuggestion idname ->
resultModelCmd ( model, setCorrOrg flags model (Just idname) )
@ -913,19 +919,15 @@ update key flags inav settings msg model =
, attachmentDropdownOpen = False
}
DeleteAttachConfirm attachId lmsg ->
DeleteAttachConfirmed attachId ->
let
( cm, confirmed ) =
Comp.YesNoDimmer.update lmsg model.deleteAttachConfirm
cmd =
if confirmed then
Api.deleteAttachment flags attachId DeleteAttachResp
else
Cmd.none
in
resultModelCmd ( { model | deleteAttachConfirm = cm }, cmd )
resultModelCmd ( { model | attachModal = Nothing }, cmd )
AttachModalCancelled ->
resultModel { model | attachModal = Nothing }
DeleteAttachResp (Ok res) ->
if res.success then
@ -938,12 +940,20 @@ update key flags inav settings msg model =
resultModel model
RequestDeleteAttachment id ->
update key
flags
inav
settings
(DeleteAttachConfirm id Comp.YesNoDimmer.activate)
{ model | attachmentDropdownOpen = False }
let
confirmModal =
Comp.ConfirmModal.defaultSettings
(DeleteAttachConfirmed id)
AttachModalCancelled
"Really delete this file?"
model_ =
{ model
| attachmentDropdownOpen = False
, attachModal = Just confirmModal
}
in
resultModel model_
AddFilesToggle ->
resultModel
@ -1508,6 +1518,73 @@ update key flags inav settings msg model =
in
resultModel { model | editMenuTabsOpen = next }
RequestReprocessFile id ->
let
confirmMsg =
if model.item.state == "created" then
"Reprocessing this file may change metadata of "
++ "this item, since it is unconfirmed. Do you want to proceed?"
else
"Reprocessing this file will not change metadata of "
++ "this item, since it has been confirmed. Do you want to proceed?"
confirmModal =
Comp.ConfirmModal.defaultSettings
(ReprocessFileConfirmed id)
AttachModalCancelled
confirmMsg
model_ =
{ model
| attachmentDropdownOpen = False
, attachModal = Just confirmModal
}
in
resultModel model_
ReprocessFileConfirmed id ->
let
cmd =
Api.reprocessItem flags model.item.id [ id ] ReprocessFileResp
in
resultModelCmd ( { model | attachModal = Nothing }, cmd )
ReprocessFileResp _ ->
resultModel model
RequestReprocessItem ->
let
confirmMsg =
if model.item.state == "created" then
"Reprocessing this item may change its metadata, "
++ "since it is unconfirmed. Do you want to proceed?"
else
"Reprocessing this item will not change its metadata, "
++ "since it has been confirmed. Do you want to proceed?"
confirmModal =
Comp.ConfirmModal.defaultSettings
ReprocessItemConfirmed
ItemModalCancelled
confirmMsg
model_ =
{ model
| attachmentDropdownOpen = False
, itemModal = Just confirmModal
}
in
resultModel model_
ReprocessItemConfirmed ->
let
cmd =
Api.reprocessItem flags model.item.id [] ReprocessFileResp
in
resultModelCmd ( { model | itemModal = Nothing }, cmd )
--- Helper

View File

@ -1,6 +1,7 @@
module Comp.ItemDetail.View2 exposing (view)
import Comp.Basic as B
import Comp.ConfirmModal
import Comp.DetailEdit
import Comp.ItemDetail.AddFilesForm
import Comp.ItemDetail.ItemInfoHeader
@ -16,7 +17,6 @@ import Comp.ItemDetail.SingleAttachment
import Comp.ItemMail
import Comp.MenuBar as MB
import Comp.SentMails
import Comp.YesNoDimmer
import Data.Icons as Icons
import Data.ItemNav exposing (ItemNav)
import Data.UiSettings exposing (UiSettings)
@ -34,15 +34,20 @@ view inav settings model =
[ header settings model
, menuBar inav settings model
, body inav settings model
, Html.map DeleteItemConfirm
(Comp.YesNoDimmer.viewN
True
(Comp.YesNoDimmer.defaultSettings2 "Really delete the complete item?")
model.deleteItemConfirm
)
, itemModal model
]
itemModal : Model -> Html Msg
itemModal model =
case model.itemModal of
Just confirm ->
Comp.ConfirmModal.view confirm
Nothing ->
span [ class "hidden" ] []
header : UiSettings -> Model -> Html Msg
header settings model =
div [ class "my-3" ]
@ -166,6 +171,15 @@ menuBar inav settings model =
]
[ i [ class "fa fa-eye-slash font-thin" ] []
]
, MB.CustomElement <|
a
[ class S.secondaryBasicButton
, href "#"
, onClick RequestReprocessItem
, title "Reprocess this item"
]
[ i [ class "fa fa-redo" ] []
]
, MB.CustomElement <|
a
[ class S.deleteButton

View File

@ -22,6 +22,7 @@ import Api.Model.BasicResult exposing (BasicResult)
import Api.Model.ItemLightList exposing (ItemLightList)
import Api.Model.SearchStats exposing (SearchStats)
import Browser.Dom as Dom
import Comp.ConfirmModal
import Comp.FixedDropdown
import Comp.ItemCardList
import Comp.ItemDetail.FormChange exposing (FormChange)
@ -64,7 +65,7 @@ type alias Model =
type alias SelectViewModel =
{ ids : Set String
, action : SelectActionMode
, deleteAllConfirm : Comp.YesNoDimmer.Model
, confirmModal : Maybe (Comp.ConfirmModal.Settings Msg)
, editModel : Comp.ItemDetail.MultiEditMenu.Model
, saveNameState : SaveNameState
, saveCustomFieldState : Set String
@ -75,7 +76,7 @@ initSelectViewModel : SelectViewModel
initSelectViewModel =
{ ids = Set.empty
, action = NoneAction
, deleteAllConfirm = Comp.YesNoDimmer.initActive
, confirmModal = Nothing
, editModel = Comp.ItemDetail.MultiEditMenu.init
, saveNameState = SaveSuccess
, saveCustomFieldState = Set.empty
@ -187,7 +188,8 @@ type Msg
| SelectAllItems
| SelectNoItems
| RequestDeleteSelected
| DeleteSelectedConfirmMsg Comp.YesNoDimmer.Msg
| DeleteSelectedConfirmed
| CloseConfirmModal
| EditSelectedItems
| EditMenuMsg Comp.ItemDetail.MultiEditMenu.Msg
| MultiUpdateResp FormChange (Result Http.Error BasicResult)
@ -199,6 +201,8 @@ type Msg
| TogglePreviewFullWidth
| PowerSearchMsg Comp.PowerSearchInput.Msg
| KeyUpPowerSearchbarMsg (Maybe KeyCode)
| RequestReprocessSelected
| ReprocessSelectedConfirmed
type SearchType
@ -210,6 +214,7 @@ type SelectActionMode
= NoneAction
| DeleteSelected
| EditSelected
| ReprocessSelected
type alias SearchParam =

View File

@ -3,6 +3,7 @@ module Page.Home.Update exposing (update)
import Api
import Api.Model.ItemLightList exposing (ItemLightList)
import Browser.Navigation as Nav
import Comp.ConfirmModal
import Comp.FixedDropdown
import Comp.ItemCardList
import Comp.ItemDetail.FormChange exposing (FormChange(..))
@ -10,7 +11,6 @@ import Comp.ItemDetail.MultiEditMenu exposing (SaveNameState(..))
import Comp.LinkTarget exposing (LinkTarget)
import Comp.PowerSearchInput
import Comp.SearchMenu
import Comp.YesNoDimmer
import Data.Flags exposing (Flags)
import Data.ItemQuery as Q
import Data.ItemSelection
@ -358,34 +358,20 @@ update mId key flags settings msg model =
_ ->
noSub ( model, Cmd.none )
DeleteSelectedConfirmMsg lmsg ->
DeleteSelectedConfirmed ->
case model.viewMode of
SelectView svm ->
let
( confirmModel, confirmed ) =
Comp.YesNoDimmer.update lmsg svm.deleteAllConfirm
cmd =
if confirmed then
Api.deleteAllItems flags svm.ids DeleteAllResp
else
Cmd.none
act =
if confirmModel.active || confirmed then
DeleteSelected
else
NoneAction
in
noSub
( { model
| viewMode =
SelectView
{ svm
| deleteAllConfirm = confirmModel
, action = act
| confirmModal = Nothing
, action = DeleteSelected
}
}
, cmd
@ -416,6 +402,74 @@ update mId key flags settings msg model =
DeleteAllResp (Err _) ->
noSub ( model, Cmd.none )
RequestReprocessSelected ->
case model.viewMode of
SelectView svm ->
if svm.ids == Set.empty then
noSub ( model, Cmd.none )
else
let
lmsg =
Comp.ConfirmModal.defaultSettings
ReprocessSelectedConfirmed
CloseConfirmModal
"Really reprocess all selected items? Metadata of unconfirmed items may change."
model_ =
{ model
| viewMode =
SelectView
{ svm
| action = ReprocessSelected
, confirmModal = Just lmsg
}
}
in
noSub ( model_, Cmd.none )
_ ->
noSub ( model, Cmd.none )
CloseConfirmModal ->
case model.viewMode of
SelectView svm ->
noSub
( { model
| viewMode = SelectView { svm | confirmModal = Nothing, action = NoneAction }
}
, Cmd.none
)
_ ->
noSub ( model, Cmd.none )
ReprocessSelectedConfirmed ->
case model.viewMode of
SelectView svm ->
if svm.ids == Set.empty then
noSub ( model, Cmd.none )
else
let
cmd =
Api.reprocessMultiple flags svm.ids DeleteAllResp
in
noSub
( { model
| viewMode =
SelectView
{ svm
| confirmModal = Nothing
, action = ReprocessSelected
}
}
, cmd
)
_ ->
noSub ( model, Cmd.none )
RequestDeleteSelected ->
case model.viewMode of
SelectView svm ->
@ -425,12 +479,22 @@ update mId key flags settings msg model =
else
let
lmsg =
DeleteSelectedConfirmMsg Comp.YesNoDimmer.activate
Comp.ConfirmModal.defaultSettings
DeleteSelectedConfirmed
CloseConfirmModal
"Really delete all selected items?"
model_ =
{ model | viewMode = SelectView { svm | action = DeleteSelected } }
{ model
| viewMode =
SelectView
{ svm
| action = DeleteSelected
, confirmModal = Just lmsg
}
}
in
update mId key flags settings lmsg model_
noSub ( model_, Cmd.none )
_ ->
noSub ( model, Cmd.none )

View File

@ -1,6 +1,7 @@
module Page.Home.View2 exposing (viewContent, viewSidebar)
import Comp.Basic as B
import Comp.ConfirmModal
import Comp.ItemCardList
import Comp.MenuBar as MB
import Comp.PowerSearchInput
@ -67,14 +68,14 @@ deleteSelectedDimmer model =
in
case model.viewMode of
SelectView svm ->
[ Html.map DeleteSelectedConfirmMsg
(Comp.YesNoDimmer.viewN
(selectAction == DeleteSelected)
deleteAllDimmer
svm.deleteAllConfirm
)
case svm.confirmModal of
Just confirm ->
[ Comp.ConfirmModal.view confirm
]
Nothing ->
[]
_ ->
[]
@ -219,6 +220,16 @@ editMenuBar model svm =
, ( "bg-gray-200 dark:bg-bluegray-600", svm.action == EditSelected )
]
}
, MB.CustomButton
{ tagger = RequestReprocessSelected
, label = ""
, icon = Just "fa fa-redo"
, title = "Reprocess " ++ selectCount ++ " selected items"
, inputClass =
[ ( btnStyle, True )
, ( "bg-gray-200 dark:bg-bluegray-600", svm.action == ReprocessSelected )
]
}
, MB.CustomButton
{ tagger = RequestDeleteSelected
, label = ""

View File

@ -313,7 +313,7 @@ editLinkTableCellStyle =
dimmer : String
dimmer =
" absolute top-0 left-0 w-full h-full bg-black bg-opacity-90 dark:bg-bluegray-900 dark:bg-opacity-90 z-50 flex flex-col items-center justify-center px-4 py-2 "
" absolute top-0 left-0 w-full h-full bg-black bg-opacity-90 dark:bg-bluegray-900 dark:bg-opacity-90 z-50 flex flex-col items-center justify-center px-4 md:px-8 py-2 "
dimmerLight : String