mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-04-04 10:29:34 +00:00
Basic ui for addons
This commit is contained in:
parent
7fdd78ad06
commit
73747c4ea3
@ -18,6 +18,14 @@ module Api exposing
|
||||
, addShare
|
||||
, addTag
|
||||
, addTagsMultiple
|
||||
, addonRunConfigDelete
|
||||
, addonRunConfigGet
|
||||
, addonRunConfigSet
|
||||
, addonRunExistingItem
|
||||
, addonsDelete
|
||||
, addonsGetAll
|
||||
, addonsInstall
|
||||
, addonsUpdate
|
||||
, attachmentPreviewURL
|
||||
, bookmarkNameExists
|
||||
, cancelJob
|
||||
@ -211,6 +219,11 @@ module Api exposing
|
||||
, versionInfo
|
||||
)
|
||||
|
||||
import Api.Model.AddonList exposing (AddonList)
|
||||
import Api.Model.AddonRegister exposing (AddonRegister)
|
||||
import Api.Model.AddonRunConfig exposing (AddonRunConfig)
|
||||
import Api.Model.AddonRunConfigList exposing (AddonRunConfigList)
|
||||
import Api.Model.AddonRunExistingItem exposing (AddonRunExistingItem)
|
||||
import Api.Model.AttachmentMeta exposing (AttachmentMeta)
|
||||
import Api.Model.AuthResult exposing (AuthResult)
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
@ -3156,6 +3169,99 @@ shareDownloadAllLink flags id =
|
||||
|
||||
|
||||
|
||||
--- Addons
|
||||
|
||||
|
||||
addonsGetAll : Flags -> (Result Http.Error AddonList -> msg) -> Cmd msg
|
||||
addonsGetAll flags receive =
|
||||
Http2.authGet
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/addon/archive"
|
||||
, account = getAccount flags
|
||||
, expect = Http.expectJson receive Api.Model.AddonList.decoder
|
||||
}
|
||||
|
||||
|
||||
addonsDelete : Flags -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
addonsDelete flags addonId receive =
|
||||
Http2.authDelete
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/addon/archive/" ++ addonId
|
||||
, account = getAccount flags
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
addonsInstall : Flags -> AddonRegister -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
addonsInstall flags addon receive =
|
||||
Http2.authPost
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/addon/archive"
|
||||
, account = getAccount flags
|
||||
, body = Http.jsonBody (Api.Model.AddonRegister.encode addon)
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
addonsUpdate : Flags -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
addonsUpdate flags addonId receive =
|
||||
Http2.authPut
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/addon/archive/" ++ addonId
|
||||
, account = getAccount flags
|
||||
, body = Http.emptyBody
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
addonRunConfigGet : Flags -> (Result Http.Error AddonRunConfigList -> msg) -> Cmd msg
|
||||
addonRunConfigGet flags receive =
|
||||
Http2.authGet
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/addon/run-config"
|
||||
, account = getAccount flags
|
||||
, expect = Http.expectJson receive Api.Model.AddonRunConfigList.decoder
|
||||
}
|
||||
|
||||
|
||||
addonRunConfigSet :
|
||||
Flags
|
||||
-> AddonRunConfig
|
||||
-> (Result Http.Error BasicResult -> msg)
|
||||
-> Cmd msg
|
||||
addonRunConfigSet flags cfg receive =
|
||||
if cfg.id == "" then
|
||||
Http2.authPost
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/addon/run-config"
|
||||
, account = getAccount flags
|
||||
, body = Http.jsonBody (Api.Model.AddonRunConfig.encode cfg)
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
else
|
||||
Http2.authPut
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/addon/run-config/" ++ cfg.id
|
||||
, account = getAccount flags
|
||||
, body = Http.jsonBody (Api.Model.AddonRunConfig.encode cfg)
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
addonRunConfigDelete : Flags -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
addonRunConfigDelete flags id receive =
|
||||
Http2.authDelete
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/addon/run-config/" ++ id
|
||||
, account = getAccount flags
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
addonRunExistingItem : Flags -> AddonRunExistingItem -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
addonRunExistingItem flags input receive =
|
||||
Http2.authPost
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/addon/run/existingitem"
|
||||
, account = getAccount flags
|
||||
, body = Http.jsonBody (Api.Model.AddonRunExistingItem.encode input)
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Helper
|
||||
|
||||
|
||||
|
@ -14,6 +14,7 @@ import Api
|
||||
import App.Data exposing (..)
|
||||
import Browser exposing (UrlRequest(..))
|
||||
import Browser.Navigation as Nav
|
||||
import Comp.AddonArchiveManage
|
||||
import Comp.DownloadAll
|
||||
import Data.AppEvent exposing (AppEvent(..))
|
||||
import Data.Environment as Env
|
||||
@ -345,6 +346,9 @@ updateWithSub msg model =
|
||||
Ok (JobsWaiting n) ->
|
||||
( { model | jobsWaiting = max 0 n }, Cmd.none, Sub.none )
|
||||
|
||||
Ok (AddonInstalled info) ->
|
||||
updateManageData (Page.ManageData.Data.AddonArchiveMsg <| Comp.AddonArchiveManage.addonInstallResult info) model
|
||||
|
||||
Err _ ->
|
||||
( model, Cmd.none, Sub.none )
|
||||
|
||||
@ -640,7 +644,7 @@ updateManageData : Page.ManageData.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Ms
|
||||
updateManageData lmsg model =
|
||||
let
|
||||
( lm, lc, ls ) =
|
||||
Page.ManageData.Update.update model.flags lmsg model.manageDataModel
|
||||
Page.ManageData.Update.update model.flags model.uiSettings lmsg model.manageDataModel
|
||||
in
|
||||
( { model | manageDataModel = lm }
|
||||
, Cmd.map ManageDataMsg lc
|
||||
|
106
modules/webapp/src/main/elm/Comp/AddonArchiveForm.elm
Normal file
106
modules/webapp/src/main/elm/Comp/AddonArchiveForm.elm
Normal file
@ -0,0 +1,106 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.AddonArchiveForm exposing (Model, Msg, get, init, initWith, update, view)
|
||||
|
||||
import Api.Model.Addon exposing (Addon)
|
||||
import Comp.Basic as B
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput)
|
||||
import Messages.Comp.AddonArchiveForm exposing (Texts)
|
||||
import Styles as S
|
||||
import Util.Maybe
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ addon : Addon
|
||||
, url : Maybe String
|
||||
}
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
( { addon = Api.Model.Addon.empty
|
||||
, url = Nothing
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
initWith : Addon -> ( Model, Cmd Msg )
|
||||
initWith a =
|
||||
( { addon = a
|
||||
, url = a.url
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
isValid : Model -> Bool
|
||||
isValid model =
|
||||
model.url /= Nothing
|
||||
|
||||
|
||||
get : Model -> Maybe Addon
|
||||
get model =
|
||||
let
|
||||
a =
|
||||
model.addon
|
||||
in
|
||||
if isValid model then
|
||||
Just
|
||||
{ a
|
||||
| url = model.url
|
||||
}
|
||||
|
||||
else
|
||||
Nothing
|
||||
|
||||
|
||||
type Msg
|
||||
= SetUrl String
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update _ msg model =
|
||||
case msg of
|
||||
SetUrl url ->
|
||||
( { model | url = Util.Maybe.fromString url }, Cmd.none )
|
||||
|
||||
|
||||
|
||||
--- View
|
||||
|
||||
|
||||
view : Texts -> Model -> Html Msg
|
||||
view texts model =
|
||||
div
|
||||
[ class "flex flex-col" ]
|
||||
[ div [ class "mb-4" ]
|
||||
[ label
|
||||
[ class S.inputLabel
|
||||
]
|
||||
[ text texts.addonUrl
|
||||
, B.inputRequired
|
||||
]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, placeholder texts.addonUrlPlaceholder
|
||||
, class S.textInput
|
||||
, classList [ ( "disabled", model.addon.id /= "" ) ]
|
||||
, value (model.url |> Maybe.withDefault "")
|
||||
, onInput SetUrl
|
||||
, disabled (model.addon.id /= "")
|
||||
]
|
||||
[]
|
||||
, span [ class "text-sm opacity-75" ]
|
||||
[ text texts.installInfoText
|
||||
]
|
||||
]
|
||||
]
|
429
modules/webapp/src/main/elm/Comp/AddonArchiveManage.elm
Normal file
429
modules/webapp/src/main/elm/Comp/AddonArchiveManage.elm
Normal file
@ -0,0 +1,429 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.AddonArchiveManage exposing (Model, Msg, addonInstallResult, init, loadAddons, update, view)
|
||||
|
||||
import Api
|
||||
import Api.Model.Addon exposing (Addon)
|
||||
import Api.Model.AddonList exposing (AddonList)
|
||||
import Api.Model.AddonRegister exposing (AddonRegister)
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Comp.AddonArchiveForm
|
||||
import Comp.AddonArchiveTable
|
||||
import Comp.Basic as B
|
||||
import Comp.ItemDetail.Model exposing (Msg(..))
|
||||
import Comp.MenuBar as MB
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.ServerEvent exposing (AddonInfo)
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Http
|
||||
import Markdown
|
||||
import Messages.Comp.AddonArchiveManage exposing (Texts)
|
||||
import Page exposing (Page(..))
|
||||
import Styles as S
|
||||
|
||||
|
||||
type FormError
|
||||
= FormErrorNone
|
||||
| FormErrorHttp Http.Error
|
||||
| FormErrorInvalid
|
||||
| FormErrorSubmit String
|
||||
|
||||
|
||||
type ViewMode
|
||||
= Table
|
||||
| Form
|
||||
|
||||
|
||||
type DeleteConfirm
|
||||
= DeleteConfirmOff
|
||||
| DeleteConfirmOn
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ viewMode : ViewMode
|
||||
, addons : List Addon
|
||||
, formModel : Comp.AddonArchiveForm.Model
|
||||
, loading : Bool
|
||||
, formError : FormError
|
||||
, deleteConfirm : DeleteConfirm
|
||||
}
|
||||
|
||||
|
||||
init : Flags -> ( Model, Cmd Msg )
|
||||
init flags =
|
||||
let
|
||||
( fm, fc ) =
|
||||
Comp.AddonArchiveForm.init
|
||||
in
|
||||
( { viewMode = Table
|
||||
, addons = []
|
||||
, formModel = fm
|
||||
, loading = False
|
||||
, formError = FormErrorNone
|
||||
, deleteConfirm = DeleteConfirmOff
|
||||
}
|
||||
, Cmd.batch
|
||||
[ Cmd.map FormMsg fc
|
||||
, Api.addonsGetAll flags LoadAddonsResp
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
type Msg
|
||||
= LoadAddons
|
||||
| TableMsg Comp.AddonArchiveTable.Msg
|
||||
| FormMsg Comp.AddonArchiveForm.Msg
|
||||
| InitNewAddon
|
||||
| SetViewMode ViewMode
|
||||
| Submit
|
||||
| RequestDelete
|
||||
| CancelDelete
|
||||
| DeleteAddonNow String
|
||||
| LoadAddonsResp (Result Http.Error AddonList)
|
||||
| AddAddonResp (Result Http.Error BasicResult)
|
||||
| UpdateAddonResp (Result Http.Error BasicResult)
|
||||
| DeleteAddonResp (Result Http.Error BasicResult)
|
||||
| AddonInstallResp AddonInfo
|
||||
|
||||
|
||||
loadAddons : Msg
|
||||
loadAddons =
|
||||
LoadAddons
|
||||
|
||||
|
||||
addonInstallResult : AddonInfo -> Msg
|
||||
addonInstallResult info =
|
||||
AddonInstallResp info
|
||||
|
||||
|
||||
|
||||
--- update
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
InitNewAddon ->
|
||||
let
|
||||
( bm, bc ) =
|
||||
Comp.AddonArchiveForm.init
|
||||
|
||||
nm =
|
||||
{ model
|
||||
| viewMode = Form
|
||||
, formError = FormErrorNone
|
||||
, formModel = bm
|
||||
}
|
||||
in
|
||||
( nm, Cmd.map FormMsg bc, Sub.none )
|
||||
|
||||
SetViewMode vm ->
|
||||
( { model | viewMode = vm, formError = FormErrorNone }
|
||||
, if vm == Table then
|
||||
Api.addonsGetAll flags LoadAddonsResp
|
||||
|
||||
else
|
||||
Cmd.none
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
FormMsg lm ->
|
||||
let
|
||||
( fm, fc ) =
|
||||
Comp.AddonArchiveForm.update flags lm model.formModel
|
||||
in
|
||||
( { model | formModel = fm, formError = FormErrorNone }
|
||||
, Cmd.map FormMsg fc
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
TableMsg lm ->
|
||||
let
|
||||
action =
|
||||
Comp.AddonArchiveTable.update lm
|
||||
in
|
||||
case action of
|
||||
Comp.AddonArchiveTable.Selected addon ->
|
||||
let
|
||||
( bm, bc ) =
|
||||
Comp.AddonArchiveForm.initWith addon
|
||||
in
|
||||
( { model
|
||||
| viewMode = Form
|
||||
, formError = FormErrorNone
|
||||
, formModel = bm
|
||||
}
|
||||
, Cmd.map FormMsg bc
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
RequestDelete ->
|
||||
( { model | deleteConfirm = DeleteConfirmOn }, Cmd.none, Sub.none )
|
||||
|
||||
CancelDelete ->
|
||||
( { model | deleteConfirm = DeleteConfirmOff }, Cmd.none, Sub.none )
|
||||
|
||||
DeleteAddonNow id ->
|
||||
( { model | deleteConfirm = DeleteConfirmOff, loading = True }
|
||||
, Api.addonsDelete flags id DeleteAddonResp
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
LoadAddons ->
|
||||
( { model | loading = True }
|
||||
, Api.addonsGetAll flags LoadAddonsResp
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
LoadAddonsResp (Ok list) ->
|
||||
( { model | loading = False, addons = list.items, formError = FormErrorNone }
|
||||
, Cmd.none
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
LoadAddonsResp (Err err) ->
|
||||
( { model | loading = False, formError = FormErrorHttp err }, Cmd.none, Sub.none )
|
||||
|
||||
AddonInstallResp info ->
|
||||
if info.success then
|
||||
( { model | loading = False, viewMode = Table }, Api.addonsGetAll flags LoadAddonsResp, Sub.none )
|
||||
|
||||
else
|
||||
( { model | loading = False, formError = FormErrorSubmit info.message }, Cmd.none, Sub.none )
|
||||
|
||||
Submit ->
|
||||
case Comp.AddonArchiveForm.get model.formModel of
|
||||
Just data ->
|
||||
if data.id /= "" then
|
||||
( { model | loading = True }
|
||||
, Api.addonsUpdate flags data.id UpdateAddonResp
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
else
|
||||
( { model | loading = True }
|
||||
, Api.addonsInstall
|
||||
flags
|
||||
(AddonRegister <| Maybe.withDefault "" data.url)
|
||||
AddAddonResp
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
Nothing ->
|
||||
( { model | formError = FormErrorInvalid }, Cmd.none, Sub.none )
|
||||
|
||||
AddAddonResp (Ok res) ->
|
||||
if res.success then
|
||||
( model, Cmd.none, Sub.none )
|
||||
|
||||
else
|
||||
( { model | loading = False, formError = FormErrorSubmit res.message }, Cmd.none, Sub.none )
|
||||
|
||||
AddAddonResp (Err err) ->
|
||||
( { model | loading = False, formError = FormErrorHttp err }, Cmd.none, Sub.none )
|
||||
|
||||
UpdateAddonResp (Ok res) ->
|
||||
if res.success then
|
||||
( model, Cmd.none, Sub.none )
|
||||
|
||||
else
|
||||
( { model | loading = False, formError = FormErrorSubmit res.message }, Cmd.none, Sub.none )
|
||||
|
||||
UpdateAddonResp (Err err) ->
|
||||
( { model | loading = False, formError = FormErrorHttp err }, Cmd.none, Sub.none )
|
||||
|
||||
DeleteAddonResp (Ok res) ->
|
||||
if res.success then
|
||||
update flags (SetViewMode Table) { model | loading = False }
|
||||
|
||||
else
|
||||
( { model | formError = FormErrorSubmit res.message, loading = False }, Cmd.none, Sub.none )
|
||||
|
||||
DeleteAddonResp (Err err) ->
|
||||
( { model | formError = FormErrorHttp err, loading = False }, Cmd.none, Sub.none )
|
||||
|
||||
|
||||
|
||||
--- view
|
||||
|
||||
|
||||
view : Texts -> UiSettings -> Flags -> Model -> Html Msg
|
||||
view texts settings flags model =
|
||||
if model.viewMode == Table then
|
||||
viewTable texts model
|
||||
|
||||
else
|
||||
viewForm texts settings flags model
|
||||
|
||||
|
||||
viewTable : Texts -> Model -> Html Msg
|
||||
viewTable texts model =
|
||||
div [ class "flex flex-col" ]
|
||||
[ MB.view
|
||||
{ start =
|
||||
[]
|
||||
, end =
|
||||
[ MB.PrimaryButton
|
||||
{ tagger = InitNewAddon
|
||||
, title = texts.createNewAddonArchive
|
||||
, icon = Just "fa fa-plus"
|
||||
, label = texts.newAddonArchive
|
||||
}
|
||||
]
|
||||
, rootClasses = "mb-4"
|
||||
, sticky = True
|
||||
}
|
||||
, div
|
||||
[ class "flex flex-col"
|
||||
]
|
||||
[ Html.map TableMsg
|
||||
(Comp.AddonArchiveTable.view texts.addonArchiveTable model.addons)
|
||||
]
|
||||
, B.loadingDimmer
|
||||
{ label = ""
|
||||
, active = model.loading
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
viewForm : Texts -> UiSettings -> Flags -> Model -> Html Msg
|
||||
viewForm texts _ _ model =
|
||||
let
|
||||
newAddon =
|
||||
model.formModel.addon.id == ""
|
||||
|
||||
isValid =
|
||||
Comp.AddonArchiveForm.get model.formModel /= Nothing
|
||||
in
|
||||
div [ class "relative" ]
|
||||
[ Html.form []
|
||||
[ if newAddon then
|
||||
h1 [ class S.header2 ]
|
||||
[ text texts.createNewAddonArchive
|
||||
]
|
||||
|
||||
else
|
||||
h1 [ class S.header2 ]
|
||||
[ text (Comp.AddonArchiveForm.get model.formModel |> Maybe.map .name |> Maybe.withDefault "Update")
|
||||
]
|
||||
, MB.view
|
||||
{ start =
|
||||
[ MB.SecondaryButton
|
||||
{ tagger = SetViewMode Table
|
||||
, title = texts.basics.backToList
|
||||
, icon = Just "fa fa-arrow-left"
|
||||
, label = texts.basics.back
|
||||
}
|
||||
]
|
||||
, end =
|
||||
if not newAddon then
|
||||
[ MB.DeleteButton
|
||||
{ tagger = RequestDelete
|
||||
, title = texts.deleteThisAddonArchive
|
||||
, icon = Just "fa fa-trash"
|
||||
, label = texts.basics.delete
|
||||
}
|
||||
]
|
||||
|
||||
else
|
||||
[]
|
||||
, rootClasses = "mb-4"
|
||||
, sticky = True
|
||||
}
|
||||
, div
|
||||
[ classList
|
||||
[ ( "hidden", model.formError == FormErrorNone )
|
||||
]
|
||||
, class "my-2"
|
||||
, class S.errorMessage
|
||||
]
|
||||
[ case model.formError of
|
||||
FormErrorNone ->
|
||||
text ""
|
||||
|
||||
FormErrorHttp err ->
|
||||
text (texts.httpError err)
|
||||
|
||||
FormErrorInvalid ->
|
||||
text texts.correctFormErrors
|
||||
|
||||
FormErrorSubmit m ->
|
||||
text m
|
||||
]
|
||||
, div []
|
||||
[ Html.map FormMsg (Comp.AddonArchiveForm.view texts.addonArchiveForm model.formModel)
|
||||
]
|
||||
, MB.view
|
||||
{ start =
|
||||
[ MB.PrimaryButton
|
||||
{ tagger = Submit
|
||||
, title = texts.installNow
|
||||
, icon =
|
||||
if newAddon then
|
||||
Just "fa fa-save"
|
||||
|
||||
else
|
||||
Just "fa fa-arrows-rotate"
|
||||
, label =
|
||||
if newAddon then
|
||||
texts.installNow
|
||||
|
||||
else
|
||||
texts.updateNow
|
||||
}
|
||||
]
|
||||
, end = []
|
||||
, rootClasses = "mb-4"
|
||||
, sticky = False
|
||||
}
|
||||
, div
|
||||
[ class "mb-4"
|
||||
, classList [ ( "hidden", newAddon ) ]
|
||||
]
|
||||
[ label [ class S.inputLabel ] [ text texts.description ]
|
||||
, case model.formModel.addon.description of
|
||||
Just desc ->
|
||||
Markdown.toHtml [ class "markdown-preview" ] desc
|
||||
|
||||
Nothing ->
|
||||
div [ class "italic" ] [ text "-" ]
|
||||
]
|
||||
, B.loadingDimmer
|
||||
{ active = model.loading
|
||||
, label = texts.basics.loading
|
||||
}
|
||||
, B.contentDimmer
|
||||
(model.deleteConfirm == DeleteConfirmOn)
|
||||
(div [ class "flex flex-col" ]
|
||||
[ div [ class "text-lg" ]
|
||||
[ i [ class "fa fa-info-circle mr-2" ] []
|
||||
, text texts.reallyDeleteAddonArchive
|
||||
]
|
||||
, div [ class "mt-4 flex flex-row items-center" ]
|
||||
[ B.deleteButton
|
||||
{ label = texts.basics.yes
|
||||
, icon = "fa fa-check"
|
||||
, disabled = False
|
||||
, handler = onClick (DeleteAddonNow model.formModel.addon.id)
|
||||
, attrs = [ href "#" ]
|
||||
}
|
||||
, B.secondaryButton
|
||||
{ label = texts.basics.no
|
||||
, icon = "fa fa-times"
|
||||
, disabled = False
|
||||
, handler = onClick CancelDelete
|
||||
, attrs = [ href "#", class "ml-2" ]
|
||||
}
|
||||
]
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
72
modules/webapp/src/main/elm/Comp/AddonArchiveTable.elm
Normal file
72
modules/webapp/src/main/elm/Comp/AddonArchiveTable.elm
Normal file
@ -0,0 +1,72 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.AddonArchiveTable exposing (..)
|
||||
|
||||
import Api.Model.Addon exposing (Addon)
|
||||
import Comp.Basic as B
|
||||
import Html exposing (Html, div, table, tbody, td, text, th, thead, tr)
|
||||
import Html.Attributes exposing (class)
|
||||
import Messages.Comp.AddonArchiveTable exposing (Texts)
|
||||
import Styles as S
|
||||
|
||||
|
||||
type Msg
|
||||
= SelectAddon Addon
|
||||
|
||||
|
||||
type TableAction
|
||||
= Selected Addon
|
||||
|
||||
|
||||
|
||||
--- Update
|
||||
|
||||
|
||||
update : Msg -> TableAction
|
||||
update msg =
|
||||
case msg of
|
||||
SelectAddon addon ->
|
||||
Selected addon
|
||||
|
||||
|
||||
|
||||
--- View
|
||||
|
||||
|
||||
view : Texts -> List Addon -> Html Msg
|
||||
view texts addons =
|
||||
table [ class S.tableMain ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "" ] []
|
||||
, th [ class "text-left" ]
|
||||
[ text texts.basics.name
|
||||
]
|
||||
, th [ class "text-left" ]
|
||||
[ text texts.version
|
||||
]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(List.map (renderAddonLine texts) addons)
|
||||
]
|
||||
|
||||
|
||||
renderAddonLine : Texts -> Addon -> Html Msg
|
||||
renderAddonLine texts addon =
|
||||
tr
|
||||
[ class S.tableRow
|
||||
]
|
||||
[ B.editLinkTableCell texts.basics.edit (SelectAddon addon)
|
||||
, td [ class "text-left py-4 md:py-2" ]
|
||||
[ text addon.name
|
||||
]
|
||||
, td [ class "text-left" ]
|
||||
[ text addon.version
|
||||
]
|
||||
]
|
709
modules/webapp/src/main/elm/Comp/AddonRunConfigForm.elm
Normal file
709
modules/webapp/src/main/elm/Comp/AddonRunConfigForm.elm
Normal file
@ -0,0 +1,709 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.AddonRunConfigForm exposing (Model, Msg, get, init, initWith, update, view)
|
||||
|
||||
import Api
|
||||
import Api.Model.Addon exposing (Addon)
|
||||
import Api.Model.AddonList exposing (AddonList)
|
||||
import Api.Model.AddonRef exposing (AddonRef)
|
||||
import Api.Model.AddonRunConfig exposing (AddonRunConfig)
|
||||
import Api.Model.User exposing (User)
|
||||
import Api.Model.UserList exposing (UserList)
|
||||
import Comp.Basic as B
|
||||
import Comp.CalEventInput
|
||||
import Comp.Dropdown
|
||||
import Comp.MenuBar as MB
|
||||
import Data.AddonTrigger exposing (AddonTrigger)
|
||||
import Data.CalEvent exposing (CalEvent)
|
||||
import Data.DropdownStyle as DS
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.TimeZone exposing (TimeZone)
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onInput)
|
||||
import Http
|
||||
import Markdown
|
||||
import Messages.Comp.AddonRunConfigForm exposing (Texts)
|
||||
import Process
|
||||
import Styles as S
|
||||
import Task
|
||||
import Util.List
|
||||
import Util.String
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ runConfig : AddonRunConfig
|
||||
, name : String
|
||||
, enabled : Bool
|
||||
, userDropdown : Comp.Dropdown.Model User
|
||||
, userId : Maybe String
|
||||
, userList : List User
|
||||
, scheduleModel : Maybe Comp.CalEventInput.Model
|
||||
, schedule : Maybe CalEvent
|
||||
, triggerDropdown : Comp.Dropdown.Model AddonTrigger
|
||||
, addons : List AddonRef
|
||||
, selectedAddon : Maybe AddonConfigModel
|
||||
, existingAddonDropdown : Comp.Dropdown.Model Addon
|
||||
, existingAddons : List Addon
|
||||
, configApplied : Bool
|
||||
}
|
||||
|
||||
|
||||
type alias AddonConfigModel =
|
||||
{ ref : AddonRef
|
||||
, position : Int
|
||||
, args : String
|
||||
, readMore : Bool
|
||||
}
|
||||
|
||||
|
||||
getRef : AddonConfigModel -> AddonRef
|
||||
getRef cfg =
|
||||
let
|
||||
a =
|
||||
cfg.ref
|
||||
in
|
||||
{ a | args = cfg.args }
|
||||
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ runConfig = Api.Model.AddonRunConfig.empty
|
||||
, name = ""
|
||||
, enabled = True
|
||||
, userDropdown = Comp.Dropdown.makeSingle
|
||||
, userId = Nothing
|
||||
, userList = []
|
||||
, scheduleModel = Nothing
|
||||
, schedule = Nothing
|
||||
, triggerDropdown =
|
||||
Comp.Dropdown.makeMultipleList
|
||||
{ options = Data.AddonTrigger.all, selected = [] }
|
||||
, addons = []
|
||||
, selectedAddon = Nothing
|
||||
, existingAddonDropdown = Comp.Dropdown.makeSingle
|
||||
, existingAddons = []
|
||||
, configApplied = False
|
||||
}
|
||||
|
||||
|
||||
init : Flags -> ( Model, Cmd Msg )
|
||||
init flags =
|
||||
( emptyModel
|
||||
, Cmd.batch
|
||||
[ Api.getUsers flags UserListResp
|
||||
, Api.addonsGetAll flags AddonListResp
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
initWith : Flags -> AddonRunConfig -> ( Model, Cmd Msg )
|
||||
initWith flags a =
|
||||
let
|
||||
ce =
|
||||
Maybe.andThen Data.CalEvent.fromEvent a.schedule
|
||||
|
||||
ceInit =
|
||||
Maybe.map (Comp.CalEventInput.init flags) ce
|
||||
|
||||
triggerModel =
|
||||
Comp.Dropdown.makeMultipleList
|
||||
{ options = Data.AddonTrigger.all
|
||||
, selected = Data.AddonTrigger.fromList a.trigger
|
||||
}
|
||||
in
|
||||
( { emptyModel
|
||||
| runConfig = a
|
||||
, name = a.name
|
||||
, enabled = a.enabled
|
||||
, scheduleModel = Maybe.map Tuple.first ceInit
|
||||
, schedule = ce
|
||||
, triggerDropdown = triggerModel
|
||||
, userId = a.userId
|
||||
, addons = a.addons
|
||||
}
|
||||
, Cmd.batch
|
||||
[ Api.getUsers flags UserListResp
|
||||
, Api.addonsGetAll flags AddonListResp
|
||||
, Maybe.map Tuple.second ceInit
|
||||
|> Maybe.map (Cmd.map ScheduleMsg)
|
||||
|> Maybe.withDefault Cmd.none
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
isValid : Model -> Bool
|
||||
isValid model =
|
||||
model.name
|
||||
/= ""
|
||||
&& (Comp.Dropdown.getSelected model.triggerDropdown
|
||||
|> List.isEmpty
|
||||
|> not
|
||||
)
|
||||
&& (List.isEmpty model.addons
|
||||
|> not
|
||||
)
|
||||
|
||||
|
||||
get : Model -> Maybe AddonRunConfig
|
||||
get model =
|
||||
let
|
||||
a =
|
||||
model.runConfig
|
||||
in
|
||||
if isValid model then
|
||||
Just
|
||||
{ a
|
||||
| name = model.name
|
||||
, enabled = model.enabled
|
||||
, schedule = Maybe.map Data.CalEvent.makeEvent model.schedule
|
||||
, trigger =
|
||||
Comp.Dropdown.getSelected model.triggerDropdown
|
||||
|> List.map Data.AddonTrigger.asString
|
||||
, userId = model.userId
|
||||
, addons = model.addons
|
||||
}
|
||||
|
||||
else
|
||||
Nothing
|
||||
|
||||
|
||||
type Msg
|
||||
= SetName String
|
||||
| UserListResp (Result Http.Error UserList)
|
||||
| AddonListResp (Result Http.Error AddonList)
|
||||
| ScheduleMsg Comp.CalEventInput.Msg
|
||||
| UserDropdownMsg (Comp.Dropdown.Msg User)
|
||||
| TriggerDropdownMsg (Comp.Dropdown.Msg AddonTrigger)
|
||||
| AddonDropdownMsg (Comp.Dropdown.Msg Addon)
|
||||
| Configure Int AddonRef
|
||||
| Up Int
|
||||
| Down Int
|
||||
| Remove Int
|
||||
| ToggleEnabled
|
||||
| ConfigSetArgs String
|
||||
| ConfigApply
|
||||
| ConfigCancel
|
||||
| AddSelectedAddon
|
||||
| ConfigToggleReadMore
|
||||
| ConfigArgsUpdated Bool
|
||||
|
||||
|
||||
|
||||
--- Update
|
||||
|
||||
|
||||
update : Flags -> TimeZone -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags tz msg model =
|
||||
case msg of
|
||||
UserListResp (Ok list) ->
|
||||
let
|
||||
um =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ options = list.items
|
||||
, selected = Nothing
|
||||
}
|
||||
in
|
||||
( { model | userDropdown = um, userList = list.items }, Cmd.none )
|
||||
|
||||
UserListResp (Err err) ->
|
||||
( model, Cmd.none )
|
||||
|
||||
AddonListResp (Ok list) ->
|
||||
let
|
||||
am =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ options = list.items
|
||||
, selected = Nothing
|
||||
}
|
||||
in
|
||||
( { model | existingAddonDropdown = am, existingAddons = list.items }, Cmd.none )
|
||||
|
||||
AddonListResp (Err err) ->
|
||||
( model, Cmd.none )
|
||||
|
||||
UserDropdownMsg lm ->
|
||||
let
|
||||
( um, cmd ) =
|
||||
Comp.Dropdown.update lm model.userDropdown
|
||||
|
||||
sel =
|
||||
Comp.Dropdown.getSelected um |> List.head
|
||||
in
|
||||
( { model | userDropdown = um, userId = Maybe.map .id sel }, Cmd.map UserDropdownMsg cmd )
|
||||
|
||||
TriggerDropdownMsg lm ->
|
||||
let
|
||||
( tm, tc ) =
|
||||
Comp.Dropdown.update lm model.triggerDropdown
|
||||
|
||||
( nm, nc ) =
|
||||
initScheduleIfNeeded flags { model | triggerDropdown = tm } tz
|
||||
in
|
||||
( nm, Cmd.batch [ Cmd.map TriggerDropdownMsg tc, nc ] )
|
||||
|
||||
ScheduleMsg lm ->
|
||||
case model.scheduleModel of
|
||||
Just m ->
|
||||
let
|
||||
( cm, cc, ce ) =
|
||||
Comp.CalEventInput.update flags tz model.schedule lm m
|
||||
in
|
||||
( { model | scheduleModel = Just cm, schedule = ce }, Cmd.map ScheduleMsg cc )
|
||||
|
||||
Nothing ->
|
||||
( model, Cmd.none )
|
||||
|
||||
ToggleEnabled ->
|
||||
( { model | enabled = not model.enabled }, Cmd.none )
|
||||
|
||||
AddonDropdownMsg lm ->
|
||||
let
|
||||
( am, ac ) =
|
||||
Comp.Dropdown.update lm model.existingAddonDropdown
|
||||
in
|
||||
( { model | existingAddonDropdown = am }, Cmd.map AddonDropdownMsg ac )
|
||||
|
||||
Configure index ref ->
|
||||
let
|
||||
cfg =
|
||||
{ ref = ref
|
||||
, position = index + 1
|
||||
, args = ref.args
|
||||
, readMore = False
|
||||
}
|
||||
in
|
||||
( { model | selectedAddon = Just cfg }, Cmd.none )
|
||||
|
||||
ConfigCancel ->
|
||||
( { model | selectedAddon = Nothing }, Cmd.none )
|
||||
|
||||
ConfigToggleReadMore ->
|
||||
case model.selectedAddon of
|
||||
Just cfg ->
|
||||
( { model | selectedAddon = Just { cfg | readMore = not cfg.readMore } }, Cmd.none )
|
||||
|
||||
Nothing ->
|
||||
( model, Cmd.none )
|
||||
|
||||
ConfigArgsUpdated flag ->
|
||||
( { model | configApplied = flag }, Cmd.none )
|
||||
|
||||
ConfigSetArgs str ->
|
||||
case model.selectedAddon of
|
||||
Just cfg ->
|
||||
( { model | selectedAddon = Just { cfg | args = str } }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Nothing ->
|
||||
( model, Cmd.none )
|
||||
|
||||
ConfigApply ->
|
||||
case model.selectedAddon of
|
||||
Just cfg ->
|
||||
let
|
||||
na =
|
||||
getRef cfg
|
||||
|
||||
addons =
|
||||
Util.List.replaceByIndex (cfg.position - 1) na model.addons
|
||||
in
|
||||
( { model | addons = addons, configApplied = True }
|
||||
, Process.sleep 1200 |> Task.perform (\_ -> ConfigArgsUpdated False)
|
||||
)
|
||||
|
||||
Nothing ->
|
||||
( model, Cmd.none )
|
||||
|
||||
AddSelectedAddon ->
|
||||
let
|
||||
sel =
|
||||
Comp.Dropdown.getSelected model.existingAddonDropdown |> List.head
|
||||
|
||||
( dm, _ ) =
|
||||
Comp.Dropdown.update (Comp.Dropdown.SetSelection []) model.existingAddonDropdown
|
||||
|
||||
addon =
|
||||
Maybe.map
|
||||
(\a ->
|
||||
{ addonId = a.id
|
||||
, name = a.name
|
||||
, version = a.version
|
||||
, description = a.description
|
||||
, args = ""
|
||||
}
|
||||
)
|
||||
sel
|
||||
|
||||
newAddons =
|
||||
Maybe.map (\e -> e :: model.addons) addon
|
||||
|> Maybe.withDefault model.addons
|
||||
in
|
||||
( { model | addons = newAddons, existingAddonDropdown = dm, selectedAddon = Nothing }, Cmd.none )
|
||||
|
||||
Up curIndex ->
|
||||
let
|
||||
newAddons =
|
||||
Util.List.changePosition curIndex (curIndex - 1) model.addons
|
||||
in
|
||||
( { model | addons = newAddons, selectedAddon = Nothing }, Cmd.none )
|
||||
|
||||
Down curIndex ->
|
||||
let
|
||||
newAddons =
|
||||
Util.List.changePosition (curIndex + 1) curIndex model.addons
|
||||
in
|
||||
( { model | addons = newAddons, selectedAddon = Nothing }, Cmd.none )
|
||||
|
||||
SetName str ->
|
||||
( { model | name = str }, Cmd.none )
|
||||
|
||||
Remove index ->
|
||||
( { model | addons = Util.List.removeByIndex index model.addons, selectedAddon = Nothing }, Cmd.none )
|
||||
|
||||
|
||||
initScheduleIfNeeded : Flags -> Model -> TimeZone -> ( Model, Cmd Msg )
|
||||
initScheduleIfNeeded flags model tz =
|
||||
let
|
||||
hasTrigger =
|
||||
Comp.Dropdown.getSelected model.triggerDropdown
|
||||
|> List.any ((==) Data.AddonTrigger.Scheduled)
|
||||
|
||||
noModel =
|
||||
model.scheduleModel == Nothing
|
||||
|
||||
hasModel =
|
||||
not noModel
|
||||
|
||||
ce =
|
||||
Data.CalEvent.everyMonthTz tz
|
||||
|
||||
( cm, cc ) =
|
||||
Comp.CalEventInput.init flags ce
|
||||
in
|
||||
if hasTrigger && noModel then
|
||||
( { model | scheduleModel = Just cm, schedule = Just ce }, Cmd.map ScheduleMsg cc )
|
||||
|
||||
else if not hasTrigger && hasModel then
|
||||
( { model | scheduleModel = Nothing, schedule = Nothing }, Cmd.none )
|
||||
|
||||
else
|
||||
( model, Cmd.none )
|
||||
|
||||
|
||||
|
||||
--- View
|
||||
|
||||
|
||||
view : Texts -> UiSettings -> Model -> Html Msg
|
||||
view texts settings model =
|
||||
let
|
||||
userDs =
|
||||
{ makeOption = \user -> { text = user.login, additional = "" }
|
||||
, placeholder = texts.basics.selectPlaceholder
|
||||
, labelColor = \_ -> \_ -> ""
|
||||
, style = DS.mainStyle
|
||||
}
|
||||
|
||||
triggerDs =
|
||||
{ makeOption = \trigger -> { text = Data.AddonTrigger.asString trigger, additional = "" }
|
||||
, placeholder = texts.basics.selectPlaceholder
|
||||
, labelColor = \_ -> \_ -> ""
|
||||
, style = DS.mainStyle
|
||||
}
|
||||
in
|
||||
div
|
||||
[ class "flex flex-col" ]
|
||||
[ div [ class "mb-4" ]
|
||||
[ div [ class "mb-4" ]
|
||||
[ label
|
||||
[ class S.inputLabel
|
||||
]
|
||||
[ text texts.basics.name
|
||||
, B.inputRequired
|
||||
]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, placeholder texts.chooseName
|
||||
, value model.name
|
||||
, onInput SetName
|
||||
, class S.textInput
|
||||
, classList [ ( S.inputErrorBorder, model.name == "" ) ]
|
||||
]
|
||||
[]
|
||||
]
|
||||
, div [ class "mb-4" ]
|
||||
[ MB.viewItem <|
|
||||
MB.Checkbox
|
||||
{ tagger = \_ -> ToggleEnabled
|
||||
, label = texts.enableDisable
|
||||
, value = model.enabled
|
||||
, id = "addon-run-config-enabled"
|
||||
}
|
||||
]
|
||||
, div [ class "mb-4" ]
|
||||
[ label
|
||||
[ class S.inputLabel
|
||||
]
|
||||
[ text texts.impersonateUser
|
||||
]
|
||||
, Html.map UserDropdownMsg
|
||||
(Comp.Dropdown.view2 userDs settings model.userDropdown)
|
||||
]
|
||||
, div [ class "mb-4" ]
|
||||
[ label
|
||||
[ class S.inputLabel
|
||||
]
|
||||
[ text texts.triggerRun
|
||||
, B.inputRequired
|
||||
]
|
||||
, Html.map TriggerDropdownMsg
|
||||
(Comp.Dropdown.view2 triggerDs settings model.triggerDropdown)
|
||||
]
|
||||
, case model.scheduleModel of
|
||||
Nothing ->
|
||||
span [ class "hidden" ] []
|
||||
|
||||
Just m ->
|
||||
div [ class "mb-4" ]
|
||||
[ label
|
||||
[ class S.inputLabel ]
|
||||
[ text texts.schedule
|
||||
]
|
||||
, Html.map ScheduleMsg (Comp.CalEventInput.view2 texts.calEventInput "" model.schedule m)
|
||||
]
|
||||
]
|
||||
, div [ class "mb-4" ]
|
||||
[ h2 [ class S.header2 ]
|
||||
[ text texts.addons ]
|
||||
, addonRef texts model
|
||||
, div [ class "mb-4" ]
|
||||
[ label [ class S.inputLabel ]
|
||||
[ text texts.includedAddons
|
||||
, B.inputRequired
|
||||
]
|
||||
, newAddon texts settings model
|
||||
, div [ class "mb-4" ]
|
||||
[ div [ class "flex flex-col mb-4" ]
|
||||
(List.indexedMap (addonLine texts model) model.addons)
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
newAddon : Texts -> UiSettings -> Model -> Html Msg
|
||||
newAddon texts uiSettings model =
|
||||
let
|
||||
addonDs =
|
||||
{ makeOption = \addon -> { text = addon.name ++ " / " ++ addon.version, additional = "" }
|
||||
, placeholder = texts.basics.selectPlaceholder
|
||||
, labelColor = \_ -> \_ -> ""
|
||||
, style = DS.mainStyle
|
||||
}
|
||||
in
|
||||
div [ class "mb-4" ]
|
||||
[ div [ class "flex flex-row" ]
|
||||
[ div [ class "flex-grow mr-2" ]
|
||||
[ Html.map AddonDropdownMsg
|
||||
(Comp.Dropdown.view2 addonDs uiSettings model.existingAddonDropdown)
|
||||
]
|
||||
, B.primaryBasicButton
|
||||
{ label = texts.add
|
||||
, icon = "fa fa-plus"
|
||||
, disabled = List.isEmpty (Comp.Dropdown.getSelected model.existingAddonDropdown)
|
||||
, handler = onClick AddSelectedAddon
|
||||
, attrs = [ href "#" ]
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
addonRef : Texts -> Model -> Html Msg
|
||||
addonRef texts model =
|
||||
let
|
||||
maybeRef =
|
||||
Maybe.map .ref model.selectedAddon
|
||||
|
||||
refInfo =
|
||||
case model.selectedAddon of
|
||||
Nothing ->
|
||||
div [ class "mb-4" ]
|
||||
[ text "[ -- ]"
|
||||
]
|
||||
|
||||
Just cfg ->
|
||||
let
|
||||
( descr, requireFolding ) =
|
||||
case cfg.ref.description of
|
||||
Just d ->
|
||||
let
|
||||
part =
|
||||
Util.String.firstSentenceOrMax 120 d
|
||||
|
||||
text =
|
||||
if cfg.readMore then
|
||||
d
|
||||
|
||||
else
|
||||
Maybe.withDefault d part
|
||||
in
|
||||
( Markdown.toHtml [ class "markdown-preview" ] text, part /= Nothing )
|
||||
|
||||
Nothing ->
|
||||
( span [ class "italic" ] [ text "No description." ], False )
|
||||
in
|
||||
div [ class "flex flex-col mb-4" ]
|
||||
[ div [ class "mt-2" ]
|
||||
[ label [ class " font-semibold py-0.5 " ]
|
||||
[ text cfg.ref.name
|
||||
, text " "
|
||||
, text cfg.ref.version
|
||||
, text " (pos. "
|
||||
, text <| String.fromInt cfg.position
|
||||
, text ")"
|
||||
, span
|
||||
[ classList [ ( "hidden", not requireFolding ) ]
|
||||
, class "ml-2"
|
||||
]
|
||||
[ a
|
||||
[ class "px-4"
|
||||
, class S.link
|
||||
, href "#"
|
||||
, onClick ConfigToggleReadMore
|
||||
]
|
||||
[ if cfg.readMore then
|
||||
text texts.readLess
|
||||
|
||||
else
|
||||
text texts.readMore
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "px-3 py-1 border-l dark:border-slate-600" ]
|
||||
[ descr
|
||||
]
|
||||
]
|
||||
]
|
||||
in
|
||||
div
|
||||
[ class "flex flex-col mb-3"
|
||||
, classList [ ( "disabled", maybeRef == Nothing ) ]
|
||||
]
|
||||
[ refInfo
|
||||
, div [ class "mb-2" ]
|
||||
[ label [ class S.inputLabel ] [ text texts.arguments ]
|
||||
, textarea
|
||||
[ Maybe.map .args model.selectedAddon |> Maybe.withDefault "" |> value
|
||||
, class S.textAreaInput
|
||||
, class "font-mono"
|
||||
, rows 8
|
||||
, onInput ConfigSetArgs
|
||||
]
|
||||
[]
|
||||
]
|
||||
, MB.view
|
||||
{ start =
|
||||
[ MB.PrimaryButton
|
||||
{ tagger = ConfigApply
|
||||
, title = ""
|
||||
, icon = Just "fa fa-save"
|
||||
, label = texts.update
|
||||
}
|
||||
, MB.SecondaryButton
|
||||
{ tagger = ConfigCancel
|
||||
, title = texts.basics.cancel
|
||||
, icon = Just "fa fa-times"
|
||||
, label = texts.basics.cancel
|
||||
}
|
||||
, MB.CustomElement <|
|
||||
div
|
||||
[ classList [ ( "hidden", not model.configApplied ) ]
|
||||
, class S.successText
|
||||
, class "inline-block min-w-fit font-semibold text-normal min-w-fit"
|
||||
]
|
||||
[ text texts.argumentsUpdated
|
||||
, i [ class "fa fa-thumbs-up ml-2" ] []
|
||||
]
|
||||
]
|
||||
, end = []
|
||||
, rootClasses = "mb-4 text-sm"
|
||||
, sticky = False
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
addonLine : Texts -> Model -> Int -> AddonRef -> Html Msg
|
||||
addonLine texts model index ref =
|
||||
let
|
||||
isSelected =
|
||||
case model.selectedAddon of
|
||||
Just cfg ->
|
||||
cfg.position - 1 == index
|
||||
|
||||
Nothing ->
|
||||
False
|
||||
in
|
||||
div
|
||||
[ class "flex flex-row items-center px-4 py-4 rounded shadow dark:border dark:border-slate-600 mb-2"
|
||||
, classList [ ( "ring-2", isSelected ) ]
|
||||
]
|
||||
[ div [ class "px-2 hidden sm:block" ]
|
||||
[ span [ class "label rounded-full opacity-75" ]
|
||||
[ text <| String.fromInt (index + 1)
|
||||
]
|
||||
]
|
||||
, div [ class "px-4 font-semibold" ]
|
||||
[ text ref.name
|
||||
, text " v"
|
||||
, text ref.version
|
||||
]
|
||||
, div [ class "flex-grow" ]
|
||||
[]
|
||||
, div [ class "px-2" ]
|
||||
[ MB.view
|
||||
{ start = []
|
||||
, end =
|
||||
[ MB.PrimaryButton
|
||||
{ tagger = Configure index ref
|
||||
, title = texts.configureTitle
|
||||
, icon = Just "fa fa-cog"
|
||||
, label = texts.configureLabel
|
||||
}
|
||||
, MB.CustomElement <|
|
||||
B.secondaryButton
|
||||
{ handler = onClick (Up index)
|
||||
, attrs = [ title "Move up", href "#" ]
|
||||
, icon = "fa fa-arrow-up"
|
||||
, label = ""
|
||||
, disabled = index == 0
|
||||
}
|
||||
, MB.CustomElement <|
|
||||
B.secondaryButton
|
||||
{ handler = onClick (Down index)
|
||||
, attrs = [ title "Move down", href "#" ]
|
||||
, icon = "fa fa-arrow-down"
|
||||
, label = ""
|
||||
, disabled = index + 1 == List.length model.addons
|
||||
}
|
||||
, MB.CustomElement <|
|
||||
B.deleteButton
|
||||
{ label = ""
|
||||
, icon = "fa fa-trash"
|
||||
, disabled = False
|
||||
, handler = onClick (Remove index)
|
||||
, attrs = [ href "#" ]
|
||||
}
|
||||
]
|
||||
, rootClasses = "text-sm"
|
||||
, sticky = False
|
||||
}
|
||||
]
|
||||
]
|
364
modules/webapp/src/main/elm/Comp/AddonRunConfigManage.elm
Normal file
364
modules/webapp/src/main/elm/Comp/AddonRunConfigManage.elm
Normal file
@ -0,0 +1,364 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.AddonRunConfigManage exposing (Model, Msg, init, loadConfigs, update, view)
|
||||
|
||||
import Api
|
||||
import Api.Model.AddonRunConfig exposing (AddonRunConfig)
|
||||
import Api.Model.AddonRunConfigList exposing (AddonRunConfigList)
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Comp.AddonRunConfigForm
|
||||
import Comp.AddonRunConfigTable
|
||||
import Comp.Basic as B
|
||||
import Comp.ItemDetail.Model exposing (Msg(..))
|
||||
import Comp.MenuBar as MB
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.TimeZone exposing (TimeZone)
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Http
|
||||
import Messages.Comp.AddonRunConfigManage exposing (Texts)
|
||||
import Page exposing (Page(..))
|
||||
import Styles as S
|
||||
|
||||
|
||||
type FormError
|
||||
= FormErrorNone
|
||||
| FormErrorHttp Http.Error
|
||||
| FormErrorInvalid
|
||||
| FormErrorSubmit String
|
||||
|
||||
|
||||
type ViewMode
|
||||
= Table
|
||||
| Form
|
||||
|
||||
|
||||
type DeleteConfirm
|
||||
= DeleteConfirmOff
|
||||
| DeleteConfirmOn
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ viewMode : ViewMode
|
||||
, runConfigs : List AddonRunConfig
|
||||
, formModel : Comp.AddonRunConfigForm.Model
|
||||
, loading : Bool
|
||||
, formError : FormError
|
||||
, deleteConfirm : DeleteConfirm
|
||||
}
|
||||
|
||||
|
||||
init : Flags -> ( Model, Cmd Msg )
|
||||
init flags =
|
||||
let
|
||||
( fm, fc ) =
|
||||
Comp.AddonRunConfigForm.init flags
|
||||
in
|
||||
( { viewMode = Table
|
||||
, runConfigs = []
|
||||
, formModel = fm
|
||||
, loading = False
|
||||
, formError = FormErrorNone
|
||||
, deleteConfirm = DeleteConfirmOff
|
||||
}
|
||||
, Cmd.batch
|
||||
[ Cmd.map FormMsg fc
|
||||
, Api.addonRunConfigGet flags LoadConfigsResp
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
type Msg
|
||||
= LoadRunConfigs
|
||||
| TableMsg Comp.AddonRunConfigTable.Msg
|
||||
| FormMsg Comp.AddonRunConfigForm.Msg
|
||||
| InitNewConfig
|
||||
| SetViewMode ViewMode
|
||||
| Submit
|
||||
| RequestDelete
|
||||
| CancelDelete
|
||||
| DeleteConfigNow String
|
||||
| LoadConfigsResp (Result Http.Error AddonRunConfigList)
|
||||
| AddConfigResp (Result Http.Error BasicResult)
|
||||
| DeleteConfigResp (Result Http.Error BasicResult)
|
||||
|
||||
|
||||
loadConfigs : Msg
|
||||
loadConfigs =
|
||||
LoadRunConfigs
|
||||
|
||||
|
||||
|
||||
--- update
|
||||
|
||||
|
||||
update : Flags -> TimeZone -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
||||
update flags tz msg model =
|
||||
case msg of
|
||||
InitNewConfig ->
|
||||
let
|
||||
( bm, bc ) =
|
||||
Comp.AddonRunConfigForm.init flags
|
||||
|
||||
nm =
|
||||
{ model
|
||||
| viewMode = Form
|
||||
, formError = FormErrorNone
|
||||
, formModel = bm
|
||||
}
|
||||
in
|
||||
( nm, Cmd.map FormMsg bc, Sub.none )
|
||||
|
||||
SetViewMode vm ->
|
||||
( { model | viewMode = vm, formError = FormErrorNone }
|
||||
, if vm == Table then
|
||||
Api.addonRunConfigGet flags LoadConfigsResp
|
||||
|
||||
else
|
||||
Cmd.none
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
FormMsg lm ->
|
||||
let
|
||||
( fm, fc ) =
|
||||
Comp.AddonRunConfigForm.update flags tz lm model.formModel
|
||||
in
|
||||
( { model | formModel = fm, formError = FormErrorNone }
|
||||
, Cmd.map FormMsg fc
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
TableMsg lm ->
|
||||
let
|
||||
action =
|
||||
Comp.AddonRunConfigTable.update lm
|
||||
in
|
||||
case action of
|
||||
Comp.AddonRunConfigTable.Selected addon ->
|
||||
let
|
||||
( bm, bc ) =
|
||||
Comp.AddonRunConfigForm.initWith flags addon
|
||||
in
|
||||
( { model
|
||||
| viewMode = Form
|
||||
, formError = FormErrorNone
|
||||
, formModel = bm
|
||||
}
|
||||
, Cmd.map FormMsg bc
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
RequestDelete ->
|
||||
( { model | deleteConfirm = DeleteConfirmOn }, Cmd.none, Sub.none )
|
||||
|
||||
CancelDelete ->
|
||||
( { model | deleteConfirm = DeleteConfirmOff }, Cmd.none, Sub.none )
|
||||
|
||||
DeleteConfigNow id ->
|
||||
( { model | deleteConfirm = DeleteConfirmOff, loading = True }
|
||||
, Api.addonRunConfigDelete flags id DeleteConfigResp
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
LoadRunConfigs ->
|
||||
( { model | loading = True }
|
||||
, Api.addonRunConfigGet flags LoadConfigsResp
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
LoadConfigsResp (Ok list) ->
|
||||
( { model | loading = False, runConfigs = list.items, formError = FormErrorNone }
|
||||
, Cmd.none
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
LoadConfigsResp (Err err) ->
|
||||
( { model | loading = False, formError = FormErrorHttp err }, Cmd.none, Sub.none )
|
||||
|
||||
Submit ->
|
||||
case Comp.AddonRunConfigForm.get model.formModel of
|
||||
Just data ->
|
||||
( { model | loading = True }, Api.addonRunConfigSet flags data AddConfigResp, Sub.none )
|
||||
|
||||
Nothing ->
|
||||
( { model | formError = FormErrorInvalid }, Cmd.none, Sub.none )
|
||||
|
||||
AddConfigResp (Ok res) ->
|
||||
if res.success then
|
||||
( { model | loading = False }, Cmd.none, Sub.none )
|
||||
|
||||
else
|
||||
( { model | loading = False, formError = FormErrorSubmit res.message }, Cmd.none, Sub.none )
|
||||
|
||||
AddConfigResp (Err err) ->
|
||||
( { model | loading = False, formError = FormErrorHttp err }, Cmd.none, Sub.none )
|
||||
|
||||
DeleteConfigResp (Ok res) ->
|
||||
if res.success then
|
||||
update flags tz (SetViewMode Table) { model | loading = False }
|
||||
|
||||
else
|
||||
( { model | formError = FormErrorSubmit res.message, loading = False }, Cmd.none, Sub.none )
|
||||
|
||||
DeleteConfigResp (Err err) ->
|
||||
( { model | formError = FormErrorHttp err, loading = False }, Cmd.none, Sub.none )
|
||||
|
||||
|
||||
|
||||
--- view
|
||||
|
||||
|
||||
view : Texts -> UiSettings -> Flags -> Model -> Html Msg
|
||||
view texts settings flags model =
|
||||
if model.viewMode == Table then
|
||||
viewTable texts model
|
||||
|
||||
else
|
||||
viewForm texts settings flags model
|
||||
|
||||
|
||||
viewTable : Texts -> Model -> Html Msg
|
||||
viewTable texts model =
|
||||
div [ class "flex flex-col" ]
|
||||
[ MB.view
|
||||
{ start =
|
||||
[]
|
||||
, end =
|
||||
[ MB.PrimaryButton
|
||||
{ tagger = InitNewConfig
|
||||
, title = texts.createNewAddonRunConfig
|
||||
, icon = Just "fa fa-plus"
|
||||
, label = texts.newAddonRunConfig
|
||||
}
|
||||
]
|
||||
, rootClasses = "mb-4"
|
||||
, sticky = True
|
||||
}
|
||||
, div
|
||||
[ class "flex flex-col"
|
||||
]
|
||||
[ Html.map TableMsg
|
||||
(Comp.AddonRunConfigTable.view texts.addonArchiveTable model.runConfigs)
|
||||
]
|
||||
, B.loadingDimmer
|
||||
{ label = ""
|
||||
, active = model.loading
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
viewForm : Texts -> UiSettings -> Flags -> Model -> Html Msg
|
||||
viewForm texts uiSettings _ model =
|
||||
let
|
||||
newConfig =
|
||||
model.formModel.runConfig.id == ""
|
||||
|
||||
isValid =
|
||||
Comp.AddonRunConfigForm.get model.formModel /= Nothing
|
||||
in
|
||||
div []
|
||||
[ Html.form []
|
||||
[ if newConfig then
|
||||
h1 [ class S.header2 ]
|
||||
[ text texts.createNewAddonRunConfig
|
||||
]
|
||||
|
||||
else
|
||||
h1 [ class S.header2 ]
|
||||
[ text (Comp.AddonRunConfigForm.get model.formModel |> Maybe.map .name |> Maybe.withDefault "Update")
|
||||
]
|
||||
, MB.view
|
||||
{ start =
|
||||
[ MB.CustomElement <|
|
||||
B.primaryButton
|
||||
{ handler = onClick Submit
|
||||
, title = texts.basics.submitThisForm
|
||||
, icon = "fa fa-save"
|
||||
, label = texts.basics.submit
|
||||
, disabled = not isValid
|
||||
, attrs = [ href "#" ]
|
||||
}
|
||||
, MB.SecondaryButton
|
||||
{ tagger = SetViewMode Table
|
||||
, title = texts.basics.backToList
|
||||
, icon = Just "fa fa-arrow-left"
|
||||
, label = texts.basics.back
|
||||
}
|
||||
]
|
||||
, end =
|
||||
if not newConfig then
|
||||
[ MB.DeleteButton
|
||||
{ tagger = RequestDelete
|
||||
, title = texts.deleteThisAddonRunConfig
|
||||
, icon = Just "fa fa-trash"
|
||||
, label = texts.basics.delete
|
||||
}
|
||||
]
|
||||
|
||||
else
|
||||
[]
|
||||
, rootClasses = "mb-4"
|
||||
, sticky = True
|
||||
}
|
||||
, div
|
||||
[ classList
|
||||
[ ( "hidden", model.formError == FormErrorNone )
|
||||
]
|
||||
, class "my-2"
|
||||
, class S.errorMessage
|
||||
]
|
||||
[ case model.formError of
|
||||
FormErrorNone ->
|
||||
text ""
|
||||
|
||||
FormErrorHttp err ->
|
||||
text (texts.httpError err)
|
||||
|
||||
FormErrorInvalid ->
|
||||
text texts.correctFormErrors
|
||||
|
||||
FormErrorSubmit m ->
|
||||
text m
|
||||
]
|
||||
, div []
|
||||
[ Html.map FormMsg (Comp.AddonRunConfigForm.view texts.addonArchiveForm uiSettings model.formModel)
|
||||
]
|
||||
, B.loadingDimmer
|
||||
{ active = model.loading
|
||||
, label = texts.basics.loading
|
||||
}
|
||||
, B.contentDimmer
|
||||
(model.deleteConfirm == DeleteConfirmOn)
|
||||
(div [ class "flex flex-col" ]
|
||||
[ div [ class "text-lg" ]
|
||||
[ i [ class "fa fa-info-circle mr-2" ] []
|
||||
, text texts.reallyDeleteAddonRunConfig
|
||||
]
|
||||
, div [ class "mt-4 flex flex-row items-center" ]
|
||||
[ B.deleteButton
|
||||
{ label = texts.basics.yes
|
||||
, icon = "fa fa-check"
|
||||
, disabled = False
|
||||
, handler = onClick (DeleteConfigNow model.formModel.runConfig.id)
|
||||
, attrs = [ href "#" ]
|
||||
}
|
||||
, B.secondaryButton
|
||||
{ label = texts.basics.no
|
||||
, icon = "fa fa-times"
|
||||
, disabled = False
|
||||
, handler = onClick CancelDelete
|
||||
, attrs = [ href "#", class "ml-2" ]
|
||||
}
|
||||
]
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
79
modules/webapp/src/main/elm/Comp/AddonRunConfigTable.elm
Normal file
79
modules/webapp/src/main/elm/Comp/AddonRunConfigTable.elm
Normal file
@ -0,0 +1,79 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.AddonRunConfigTable exposing (..)
|
||||
|
||||
import Api.Model.AddonRunConfig exposing (AddonRunConfig)
|
||||
import Comp.Basic as B
|
||||
import Html exposing (Html, div, table, tbody, td, text, th, thead, tr)
|
||||
import Html.Attributes exposing (class)
|
||||
import Messages.Comp.AddonRunConfigTable exposing (Texts)
|
||||
import Styles as S
|
||||
import Util.Html
|
||||
|
||||
|
||||
type Msg
|
||||
= SelectRunConfig AddonRunConfig
|
||||
|
||||
|
||||
type TableAction
|
||||
= Selected AddonRunConfig
|
||||
|
||||
|
||||
|
||||
--- Update
|
||||
|
||||
|
||||
update : Msg -> TableAction
|
||||
update msg =
|
||||
case msg of
|
||||
SelectRunConfig cfg ->
|
||||
Selected cfg
|
||||
|
||||
|
||||
|
||||
--- View
|
||||
|
||||
|
||||
view : Texts -> List AddonRunConfig -> Html Msg
|
||||
view texts addons =
|
||||
table [ class S.tableMain ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "" ] []
|
||||
, th [ class "text-left" ]
|
||||
[ text texts.basics.name
|
||||
]
|
||||
, th [ class "px-2 text-center" ] [ text texts.enabled ]
|
||||
, th [ class "px-2 text-left" ] [ text texts.trigger ]
|
||||
, th [ class "px-2 text-center" ] [ text "# Addons" ]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(List.map (renderRunConfigLine texts) addons)
|
||||
]
|
||||
|
||||
|
||||
renderRunConfigLine : Texts -> AddonRunConfig -> Html Msg
|
||||
renderRunConfigLine texts cfg =
|
||||
tr
|
||||
[ class S.tableRow
|
||||
]
|
||||
[ B.editLinkTableCell texts.basics.edit (SelectRunConfig cfg)
|
||||
, td [ class "text-left py-4 md:py-2" ]
|
||||
[ text cfg.name
|
||||
]
|
||||
, td [ class "w-px whitespace-nowrap px-2 text-center" ]
|
||||
[ Util.Html.checkbox2 cfg.enabled
|
||||
]
|
||||
, td [ class "px-2 text-left" ]
|
||||
[ text (String.join ", " cfg.trigger)
|
||||
]
|
||||
, td [ class "px-2 text-center" ]
|
||||
[ text (String.fromInt <| List.length cfg.addons)
|
||||
]
|
||||
]
|
@ -28,6 +28,8 @@ module Comp.ItemDetail.Model exposing
|
||||
, resultModelCmdSub
|
||||
)
|
||||
|
||||
import Api.Model.AddonRunConfig exposing (AddonRunConfig)
|
||||
import Api.Model.AddonRunConfigList exposing (AddonRunConfigList)
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.CustomField exposing (CustomField)
|
||||
import Api.Model.EquipmentList exposing (EquipmentList)
|
||||
@ -72,6 +74,7 @@ import Set exposing (Set)
|
||||
|
||||
type alias Model =
|
||||
{ item : ItemDetail
|
||||
, runConfigs : List AddonRunConfig
|
||||
, visibleAttach : Int
|
||||
, attachMenuOpen : Bool
|
||||
, menuOpen : Bool
|
||||
@ -123,6 +126,9 @@ type alias Model =
|
||||
, viewMode : ViewMode
|
||||
, showQrModel : ShowQrModel
|
||||
, itemLinkModel : Comp.ItemLinkForm.Model
|
||||
, showRunAddon : Bool
|
||||
, addonRunConfigDropdown : Comp.Dropdown.Model AddonRunConfig
|
||||
, addonRunSubmitted : Bool
|
||||
}
|
||||
|
||||
|
||||
@ -204,6 +210,7 @@ isEditNotes field =
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ item = Api.Model.ItemDetail.empty
|
||||
, runConfigs = []
|
||||
, visibleAttach = 0
|
||||
, attachMenuOpen = False
|
||||
, menuOpen = False
|
||||
@ -259,6 +266,9 @@ emptyModel =
|
||||
, viewMode = SimpleView
|
||||
, showQrModel = initShowQrModel
|
||||
, itemLinkModel = Comp.ItemLinkForm.emptyModel
|
||||
, showRunAddon = False
|
||||
, addonRunConfigDropdown = Comp.Dropdown.makeSingle
|
||||
, addonRunSubmitted = False
|
||||
}
|
||||
|
||||
|
||||
@ -373,6 +383,12 @@ type Msg
|
||||
| SetNameMsg Comp.SimpleTextInput.Msg
|
||||
| ToggleSelectItem
|
||||
| ItemLinkFormMsg Comp.ItemLinkForm.Msg
|
||||
| ToggleShowRunAddon
|
||||
| LoadRunConfigResp (Result Http.Error AddonRunConfigList)
|
||||
| RunAddonMsg (Comp.Dropdown.Msg AddonRunConfig)
|
||||
| RunSelectedAddon
|
||||
| RunAddonResp (Result Http.Error BasicResult)
|
||||
| SetAddonRunSubmitted Bool
|
||||
|
||||
|
||||
type SaveNameState
|
||||
|
78
modules/webapp/src/main/elm/Comp/ItemDetail/RunAddonForm.elm
Normal file
78
modules/webapp/src/main/elm/Comp/ItemDetail/RunAddonForm.elm
Normal file
@ -0,0 +1,78 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.ItemDetail.RunAddonForm exposing (..)
|
||||
|
||||
import Comp.Basic as B
|
||||
import Comp.Dropdown
|
||||
import Comp.ItemDetail.Model exposing (..)
|
||||
import Comp.MenuBar as MB
|
||||
import Data.DropdownStyle as DS
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Html exposing (Html, div, h3, label, text)
|
||||
import Html.Attributes exposing (class, classList, title)
|
||||
import Html.Events exposing (onClick)
|
||||
import Messages.Comp.ItemDetail.RunAddonForm exposing (Texts)
|
||||
import Styles as S
|
||||
|
||||
|
||||
view : Texts -> UiSettings -> Model -> Html Msg
|
||||
view texts uiSettings model =
|
||||
let
|
||||
viewSettings =
|
||||
{ makeOption = \cfg -> { text = cfg.name, additional = "" }
|
||||
, placeholder = texts.basics.selectPlaceholder
|
||||
, labelColor = \_ -> \_ -> ""
|
||||
, style = DS.mainStyle
|
||||
}
|
||||
|
||||
runDisabled =
|
||||
Comp.Dropdown.getSelected model.addonRunConfigDropdown
|
||||
|> List.isEmpty
|
||||
in
|
||||
div
|
||||
[ classList [ ( "hidden", not model.showRunAddon ) ]
|
||||
, class "mb-4"
|
||||
]
|
||||
[ h3 [ class S.header3 ] [ text texts.runAddon ]
|
||||
, div [ class "my-2" ]
|
||||
[ label [ class S.inputLabel ]
|
||||
[ text texts.addonRunConfig
|
||||
]
|
||||
, Html.map RunAddonMsg (Comp.Dropdown.view2 viewSettings uiSettings model.addonRunConfigDropdown)
|
||||
]
|
||||
, div [ class "my-2" ]
|
||||
[ MB.view
|
||||
{ start =
|
||||
[ MB.CustomElement <|
|
||||
B.primaryButton
|
||||
{ label = "Run"
|
||||
, icon =
|
||||
if model.addonRunSubmitted then
|
||||
"fa fa-check"
|
||||
|
||||
else
|
||||
"fa fa-play"
|
||||
, disabled = runDisabled
|
||||
, handler = onClick RunSelectedAddon
|
||||
, attrs =
|
||||
[ title texts.runAddonTitle
|
||||
]
|
||||
}
|
||||
, MB.SecondaryButton
|
||||
{ label = texts.basics.cancel
|
||||
, icon = Just "fa fa-times"
|
||||
, tagger = ToggleShowRunAddon
|
||||
, title = ""
|
||||
}
|
||||
]
|
||||
, end = []
|
||||
, rootClasses = "text-sm mt-1"
|
||||
, sticky = False
|
||||
}
|
||||
]
|
||||
]
|
@ -56,6 +56,7 @@ import Comp.PersonForm
|
||||
import Comp.SentMails
|
||||
import Comp.SimpleTextInput
|
||||
import Comp.TagDropdown
|
||||
import Data.AddonTrigger
|
||||
import Data.CustomFieldChange exposing (CustomFieldChange(..))
|
||||
import Data.Direction
|
||||
import Data.Environment as Env
|
||||
@ -75,7 +76,9 @@ import Html5.DragDrop as DD
|
||||
import Http
|
||||
import Page exposing (Page(..))
|
||||
import Ports
|
||||
import Process
|
||||
import Set exposing (Set)
|
||||
import Task
|
||||
import Util.File exposing (makeFileId)
|
||||
import Util.List
|
||||
import Util.Maybe
|
||||
@ -121,9 +124,77 @@ update inav env msg model =
|
||||
, Cmd.map ItemMailMsg ic
|
||||
, Cmd.map CustomFieldMsg cc
|
||||
, Api.getSentMails env.flags model.item.id SentMailsResp
|
||||
, Api.addonRunConfigGet env.flags LoadRunConfigResp
|
||||
]
|
||||
)
|
||||
|
||||
LoadRunConfigResp (Ok list) ->
|
||||
let
|
||||
existingItem cfg =
|
||||
cfg.enabled
|
||||
&& (Data.AddonTrigger.fromList cfg.trigger
|
||||
|> List.any ((==) Data.AddonTrigger.ExistingItem)
|
||||
)
|
||||
|
||||
configs =
|
||||
List.filter existingItem list.items
|
||||
|
||||
dropdown =
|
||||
Comp.Dropdown.makeSingleList { options = configs, selected = Nothing }
|
||||
in
|
||||
resultModel { model | runConfigs = configs, addonRunConfigDropdown = dropdown }
|
||||
|
||||
RunAddonMsg lm ->
|
||||
let
|
||||
( dd, dc ) =
|
||||
Comp.Dropdown.update lm model.addonRunConfigDropdown
|
||||
in
|
||||
resultModelCmd ( { model | addonRunConfigDropdown = dd }, Cmd.map RunAddonMsg dc )
|
||||
|
||||
RunSelectedAddon ->
|
||||
let
|
||||
configs =
|
||||
Comp.Dropdown.getSelected model.addonRunConfigDropdown
|
||||
|> List.map .id
|
||||
|
||||
payload =
|
||||
{ itemId = model.item.id
|
||||
, additionalItems = []
|
||||
, addonRunConfigIds = configs
|
||||
}
|
||||
|
||||
( dd, _ ) =
|
||||
Comp.Dropdown.update (Comp.Dropdown.SetSelection []) model.addonRunConfigDropdown
|
||||
in
|
||||
case configs of
|
||||
[] ->
|
||||
resultModel model
|
||||
|
||||
_ ->
|
||||
resultModelCmd
|
||||
( { model | addonRunConfigDropdown = dd }
|
||||
, Api.addonRunExistingItem env.flags payload RunAddonResp
|
||||
)
|
||||
|
||||
LoadRunConfigResp (Err _) ->
|
||||
resultModel model
|
||||
|
||||
RunAddonResp (Ok res) ->
|
||||
if res.success then
|
||||
resultModelCmd
|
||||
( { model | addonRunSubmitted = True }
|
||||
, Process.sleep 1200 |> Task.perform (\_ -> SetAddonRunSubmitted False)
|
||||
)
|
||||
|
||||
else
|
||||
resultModel model
|
||||
|
||||
RunAddonResp (Err _) ->
|
||||
resultModel model
|
||||
|
||||
SetAddonRunSubmitted flag ->
|
||||
resultModel { model | addonRunSubmitted = flag }
|
||||
|
||||
SetItem item ->
|
||||
let
|
||||
res1 =
|
||||
@ -1638,6 +1709,9 @@ update inav env msg model =
|
||||
, Sub.map ItemLinkFormMsg ils
|
||||
)
|
||||
|
||||
ToggleShowRunAddon ->
|
||||
resultModel { model | showRunAddon = not model.showRunAddon, mobileItemMenuOpen = False }
|
||||
|
||||
|
||||
|
||||
--- Helper
|
||||
|
@ -22,6 +22,7 @@ import Comp.ItemDetail.Model
|
||||
, isShowQrItem
|
||||
)
|
||||
import Comp.ItemDetail.Notes
|
||||
import Comp.ItemDetail.RunAddonForm
|
||||
import Comp.ItemDetail.ShowQrCode
|
||||
import Comp.ItemDetail.SingleAttachment
|
||||
import Comp.ItemLinkForm
|
||||
@ -177,6 +178,24 @@ menuBar texts inav env model =
|
||||
]
|
||||
[ Icons.addFilesIcon2 ""
|
||||
]
|
||||
, MB.CustomElement <|
|
||||
a
|
||||
[ classList
|
||||
[ ( "bg-gray-200 dark:bg-slate-600", model.showRunAddon )
|
||||
, ( "hidden", not env.flags.config.addonsEnabled || List.isEmpty model.runConfigs )
|
||||
, ( "hidden md:block", env.flags.config.addonsEnabled && not (List.isEmpty model.runConfigs) )
|
||||
]
|
||||
, if model.showRunAddon then
|
||||
title texts.close
|
||||
|
||||
else
|
||||
title texts.runAddonTitle
|
||||
, onClick ToggleShowRunAddon
|
||||
, class S.secondaryBasicButton
|
||||
, href "#"
|
||||
]
|
||||
[ Icons.addonIcon ""
|
||||
]
|
||||
, MB.CustomElement <|
|
||||
a
|
||||
[ classList
|
||||
@ -248,6 +267,15 @@ menuBar texts inav env model =
|
||||
, onClick AddFilesToggle
|
||||
]
|
||||
}
|
||||
, { icon = Icons.addonIcon ""
|
||||
, label = texts.runAddonLabel
|
||||
, disabled = False
|
||||
, attrs =
|
||||
[ href "#"
|
||||
, onClick ToggleShowRunAddon
|
||||
, classList [ ( "hidden", not env.flags.config.addonsEnabled ) ]
|
||||
]
|
||||
}
|
||||
, { icon = Icons.showQrIcon ""
|
||||
, label = texts.showQrCode
|
||||
, disabled = False
|
||||
@ -402,6 +430,11 @@ itemActions texts flags settings model classes =
|
||||
(S.border ++ " mb-4")
|
||||
model
|
||||
(Comp.ItemDetail.ShowQrCode.Item model.item.id)
|
||||
, if flags.config.addonsEnabled then
|
||||
Comp.ItemDetail.RunAddonForm.view texts.runAddonForm settings model
|
||||
|
||||
else
|
||||
span [ class "hidden" ] []
|
||||
]
|
||||
|
||||
|
||||
|
59
modules/webapp/src/main/elm/Data/AddonTrigger.elm
Normal file
59
modules/webapp/src/main/elm/Data/AddonTrigger.elm
Normal file
@ -0,0 +1,59 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Data.AddonTrigger exposing (..)
|
||||
|
||||
-- A copy of docspell.addons.AddonTrigger.scala
|
||||
|
||||
|
||||
type AddonTrigger
|
||||
= FinalProcessItem
|
||||
| FinalReprocessItem
|
||||
| Scheduled
|
||||
| ExistingItem
|
||||
|
||||
|
||||
all : List AddonTrigger
|
||||
all =
|
||||
[ FinalProcessItem
|
||||
, FinalReprocessItem
|
||||
, Scheduled
|
||||
, ExistingItem
|
||||
]
|
||||
|
||||
|
||||
asString : AddonTrigger -> String
|
||||
asString t =
|
||||
case t of
|
||||
FinalProcessItem ->
|
||||
"final-process-item"
|
||||
|
||||
FinalReprocessItem ->
|
||||
"final-reprocess-item"
|
||||
|
||||
Scheduled ->
|
||||
"scheduled"
|
||||
|
||||
ExistingItem ->
|
||||
"existing-item"
|
||||
|
||||
|
||||
fromString : String -> Maybe AddonTrigger
|
||||
fromString s =
|
||||
let
|
||||
name =
|
||||
String.toLower s
|
||||
|
||||
x =
|
||||
List.filter (\e -> asString e == name) all
|
||||
in
|
||||
List.head x
|
||||
|
||||
|
||||
fromList : List String -> List AddonTrigger
|
||||
fromList list =
|
||||
List.filterMap fromString list
|
@ -8,6 +8,7 @@
|
||||
module Data.CalEvent exposing
|
||||
( CalEvent
|
||||
, everyMonth
|
||||
, everyMonthTz
|
||||
, fromEvent
|
||||
, makeEvent
|
||||
)
|
||||
@ -29,7 +30,12 @@ type alias CalEvent =
|
||||
|
||||
everyMonth : CalEvent
|
||||
everyMonth =
|
||||
CalEvent Nothing "*" "*" "01" "00" "00" Data.TimeZone.utc
|
||||
everyMonthTz Data.TimeZone.utc
|
||||
|
||||
|
||||
everyMonthTz : TimeZone -> CalEvent
|
||||
everyMonthTz tz =
|
||||
CalEvent Nothing "*" "*" "01" "00" "00" tz
|
||||
|
||||
|
||||
makeEvent : CalEvent -> String
|
||||
|
@ -38,6 +38,7 @@ type alias Config =
|
||||
, downloadAllMaxFiles : Int
|
||||
, downloadAllMaxSize : Int
|
||||
, openIdAuth : List OpenIdAuth
|
||||
, addonsEnabled : Bool
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
module Data.Icons exposing
|
||||
( addFiles2
|
||||
, addFilesIcon2
|
||||
, addonIcon
|
||||
, addonRunConfigIcon
|
||||
, concerned
|
||||
, concerned2
|
||||
, concernedIcon
|
||||
@ -76,7 +78,7 @@ module Data.Icons exposing
|
||||
)
|
||||
|
||||
import Data.CustomFieldType exposing (CustomFieldType)
|
||||
import Html exposing (Html, i, img)
|
||||
import Html exposing (Html, div, i, img, span)
|
||||
import Html.Attributes exposing (class, src)
|
||||
import Svg
|
||||
import Svg.Attributes as SA
|
||||
@ -265,6 +267,24 @@ customFieldIcon2 classes =
|
||||
i [ class (customField2 ++ " " ++ classes) ] []
|
||||
|
||||
|
||||
addon : String
|
||||
addon =
|
||||
"fa fa-puzzle-piece"
|
||||
|
||||
|
||||
addonIcon : String -> Html msg
|
||||
addonIcon classes =
|
||||
i [ class (addon ++ " " ++ classes) ] []
|
||||
|
||||
|
||||
addonRunConfigIcon : String -> Html msg
|
||||
addonRunConfigIcon classes =
|
||||
div [ class (classes ++ " inline-block relative margin-auto leading-8") ]
|
||||
[ i [ class "fa fa-puzzle-piece" ] []
|
||||
, i [ class "fa fa-play font-bold absolute text-xs -right-2 top-0" ] []
|
||||
]
|
||||
|
||||
|
||||
search : String
|
||||
search =
|
||||
"fa fa-search"
|
||||
|
@ -5,15 +5,34 @@
|
||||
-}
|
||||
|
||||
|
||||
module Data.ServerEvent exposing (ServerEvent(..), decode)
|
||||
module Data.ServerEvent exposing (AddonInfo, ServerEvent(..), decode)
|
||||
|
||||
import Json.Decode as D
|
||||
import Json.Decode.Pipeline as P
|
||||
|
||||
|
||||
type ServerEvent
|
||||
= JobSubmitted String
|
||||
| JobDone String
|
||||
| JobsWaiting Int
|
||||
| AddonInstalled AddonInfo
|
||||
|
||||
|
||||
type alias AddonInfo =
|
||||
{ success : Bool
|
||||
, addonId : Maybe String
|
||||
, addonUrl : Maybe String
|
||||
, message : String
|
||||
}
|
||||
|
||||
|
||||
addonInfoDecoder : D.Decoder AddonInfo
|
||||
addonInfoDecoder =
|
||||
D.succeed AddonInfo
|
||||
|> P.required "success" D.bool
|
||||
|> P.optional "addonId" (D.maybe D.string) Nothing
|
||||
|> P.optional "addonUrl" (D.maybe D.string) Nothing
|
||||
|> P.required "message" D.string
|
||||
|
||||
|
||||
decoder : D.Decoder ServerEvent
|
||||
@ -43,5 +62,9 @@ decodeTag tag =
|
||||
D.field "content" D.int
|
||||
|> D.map JobsWaiting
|
||||
|
||||
"addon-installed" ->
|
||||
D.field "content" addonInfoDecoder
|
||||
|> D.map AddonInstalled
|
||||
|
||||
_ ->
|
||||
D.fail ("Unknown tag: " ++ tag)
|
||||
|
@ -0,0 +1,54 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Messages.Comp.AddonArchiveForm exposing
|
||||
( Texts
|
||||
, de
|
||||
, fr
|
||||
, gb
|
||||
)
|
||||
|
||||
import Messages.Basics
|
||||
|
||||
|
||||
type alias Texts =
|
||||
{ basics : Messages.Basics.Texts
|
||||
, addonUrl : String
|
||||
, addonUrlPlaceholder : String
|
||||
, installInfoText : String
|
||||
}
|
||||
|
||||
|
||||
gb : Texts
|
||||
gb =
|
||||
{ basics = Messages.Basics.gb
|
||||
, addonUrl = "Addon URL"
|
||||
, addonUrlPlaceholder = "e.g. https://github.com/some-user/project/refs/tags/1.0.zip"
|
||||
, installInfoText = "Only urls to remote addon zip files are supported."
|
||||
}
|
||||
|
||||
|
||||
de : Texts
|
||||
de =
|
||||
{ basics = Messages.Basics.de
|
||||
, addonUrl = "Addon URL"
|
||||
, addonUrlPlaceholder = "z.B. https://github.com/some-user/project/refs/tags/1.0.zip"
|
||||
, installInfoText = "Nur URLs to externen zip Dateien werden unterstützt."
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- TODO: translate-fr
|
||||
|
||||
|
||||
fr : Texts
|
||||
fr =
|
||||
{ basics = Messages.Basics.fr
|
||||
, addonUrl = "Addon URL"
|
||||
, addonUrlPlaceholder = "p.e. https://github.com/some-user/project/refs/tags/1.0.zip"
|
||||
, installInfoText = "Only urls to remote addon zip files are supported."
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Messages.Comp.AddonArchiveManage exposing
|
||||
( Texts
|
||||
, de
|
||||
, fr
|
||||
, gb
|
||||
)
|
||||
|
||||
import Http
|
||||
import Messages.Basics
|
||||
import Messages.Comp.AddonArchiveForm
|
||||
import Messages.Comp.AddonArchiveTable
|
||||
import Messages.Comp.HttpError
|
||||
|
||||
|
||||
type alias Texts =
|
||||
{ basics : Messages.Basics.Texts
|
||||
, addonArchiveTable : Messages.Comp.AddonArchiveTable.Texts
|
||||
, addonArchiveForm : Messages.Comp.AddonArchiveForm.Texts
|
||||
, httpError : Http.Error -> String
|
||||
, newAddonArchive : String
|
||||
, reallyDeleteAddonArchive : String
|
||||
, createNewAddonArchive : String
|
||||
, deleteThisAddonArchive : String
|
||||
, correctFormErrors : String
|
||||
, installNow : String
|
||||
, updateNow : String
|
||||
, description : String
|
||||
}
|
||||
|
||||
|
||||
gb : Texts
|
||||
gb =
|
||||
{ basics = Messages.Basics.gb
|
||||
, addonArchiveTable = Messages.Comp.AddonArchiveTable.gb
|
||||
, addonArchiveForm = Messages.Comp.AddonArchiveForm.gb
|
||||
, httpError = Messages.Comp.HttpError.gb
|
||||
, newAddonArchive = "New Addon"
|
||||
, reallyDeleteAddonArchive = "Really delete this Addon?"
|
||||
, createNewAddonArchive = "Install new Addon"
|
||||
, deleteThisAddonArchive = "Delete this Addon"
|
||||
, correctFormErrors = "Please correct the errors in the form."
|
||||
, installNow = "Install Addon"
|
||||
, updateNow = "Update Addon"
|
||||
, description = "Description"
|
||||
}
|
||||
|
||||
|
||||
de : Texts
|
||||
de =
|
||||
{ basics = Messages.Basics.de
|
||||
, addonArchiveTable = Messages.Comp.AddonArchiveTable.de
|
||||
, addonArchiveForm = Messages.Comp.AddonArchiveForm.de
|
||||
, httpError = Messages.Comp.HttpError.de
|
||||
, newAddonArchive = "Neues Addon"
|
||||
, reallyDeleteAddonArchive = "Dieses Addon wirklich entfernen?"
|
||||
, createNewAddonArchive = "Neues Addon installieren"
|
||||
, deleteThisAddonArchive = "Addon löschen"
|
||||
, correctFormErrors = "Bitte korrigiere die Fehler im Formular."
|
||||
, installNow = "Addon Installieren"
|
||||
, updateNow = "Addon aktualisieren"
|
||||
, description = "Beschreibung"
|
||||
}
|
||||
|
||||
|
||||
fr : Texts
|
||||
fr =
|
||||
{ basics = Messages.Basics.fr
|
||||
, addonArchiveTable = Messages.Comp.AddonArchiveTable.fr
|
||||
, addonArchiveForm = Messages.Comp.AddonArchiveForm.fr
|
||||
, httpError = Messages.Comp.HttpError.fr
|
||||
, newAddonArchive = "Nouveau favori"
|
||||
, reallyDeleteAddonArchive = "Confirmer la suppression de ce favori ?"
|
||||
, createNewAddonArchive = "Créer un nouveau favori"
|
||||
, deleteThisAddonArchive = "Supprimer ce favori"
|
||||
, correctFormErrors = "Veuillez corriger les erreurs du formulaire"
|
||||
, installNow = "Installation de l'addon"
|
||||
, updateNow = "Actualiser l'addon"
|
||||
, description = "Description"
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Messages.Comp.AddonArchiveTable exposing
|
||||
( Texts
|
||||
, de
|
||||
, fr
|
||||
, gb
|
||||
)
|
||||
|
||||
import Messages.Basics
|
||||
|
||||
|
||||
type alias Texts =
|
||||
{ basics : Messages.Basics.Texts
|
||||
, version : String
|
||||
}
|
||||
|
||||
|
||||
gb : Texts
|
||||
gb =
|
||||
{ basics = Messages.Basics.gb
|
||||
, version = "Version"
|
||||
}
|
||||
|
||||
|
||||
de : Texts
|
||||
de =
|
||||
{ basics = Messages.Basics.de
|
||||
, version = "Version"
|
||||
}
|
||||
|
||||
|
||||
fr : Texts
|
||||
fr =
|
||||
{ basics = Messages.Basics.fr
|
||||
, version = "Version"
|
||||
}
|
108
modules/webapp/src/main/elm/Messages/Comp/AddonRunConfigForm.elm
Normal file
108
modules/webapp/src/main/elm/Messages/Comp/AddonRunConfigForm.elm
Normal file
@ -0,0 +1,108 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Messages.Comp.AddonRunConfigForm exposing
|
||||
( Texts
|
||||
, de
|
||||
, fr
|
||||
, gb
|
||||
)
|
||||
|
||||
import Data.TimeZone exposing (TimeZone)
|
||||
import Messages.Basics
|
||||
import Messages.Comp.CalEventInput
|
||||
|
||||
|
||||
type alias Texts =
|
||||
{ basics : Messages.Basics.Texts
|
||||
, calEventInput : Messages.Comp.CalEventInput.Texts
|
||||
, enableDisable : String
|
||||
, chooseName : String
|
||||
, impersonateUser : String
|
||||
, triggerRun : String
|
||||
, schedule : String
|
||||
, addons : String
|
||||
, includedAddons : String
|
||||
, add : String
|
||||
, readMore : String
|
||||
, readLess : String
|
||||
, arguments : String
|
||||
, update : String
|
||||
, argumentsUpdated : String
|
||||
, configureTitle : String
|
||||
, configureLabel : String
|
||||
}
|
||||
|
||||
|
||||
gb : TimeZone -> Texts
|
||||
gb tz =
|
||||
{ basics = Messages.Basics.gb
|
||||
, calEventInput = Messages.Comp.CalEventInput.gb tz
|
||||
, enableDisable = "Enable or disable this run configuration."
|
||||
, chooseName = "Choose a name…"
|
||||
, impersonateUser = "Run on behalf of user"
|
||||
, triggerRun = "Trigger Run"
|
||||
, schedule = "Schedule"
|
||||
, addons = "Addons"
|
||||
, includedAddons = "Included addons"
|
||||
, add = "Add"
|
||||
, readMore = "Read more"
|
||||
, readLess = "Read less"
|
||||
, arguments = "Arguments"
|
||||
, update = "Update"
|
||||
, argumentsUpdated = "Arguments updated"
|
||||
, configureTitle = "Configure this addon"
|
||||
, configureLabel = "Configure"
|
||||
}
|
||||
|
||||
|
||||
de : TimeZone -> Texts
|
||||
de tz =
|
||||
{ basics = Messages.Basics.de
|
||||
, calEventInput = Messages.Comp.CalEventInput.de tz
|
||||
, enableDisable = "Konfiguration aktivieren oder deaktivieren"
|
||||
, chooseName = "Name der Konfiguration…"
|
||||
, impersonateUser = "Als Benutzer ausführen"
|
||||
, triggerRun = "Auslöser"
|
||||
, schedule = "Zeitplan"
|
||||
, addons = "Addons"
|
||||
, includedAddons = "Gewählte Addons"
|
||||
, add = "Hinzufügen"
|
||||
, readMore = "Mehr"
|
||||
, readLess = "Weniger"
|
||||
, arguments = "Argumente"
|
||||
, update = "Aktualisieren"
|
||||
, argumentsUpdated = "Argumente aktualisiert"
|
||||
, configureTitle = "Konfiguriere dieses Addon"
|
||||
, configureLabel = "Konfigurieren"
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- TODO: translate-fr
|
||||
|
||||
|
||||
fr : TimeZone -> Texts
|
||||
fr tz =
|
||||
{ basics = Messages.Basics.fr
|
||||
, calEventInput = Messages.Comp.CalEventInput.fr tz
|
||||
, enableDisable = "Activer ou désactiver cette tâche."
|
||||
, chooseName = "Choose a name…"
|
||||
, impersonateUser = "Impersonate user"
|
||||
, triggerRun = "Trigger Run"
|
||||
, schedule = "Programmation"
|
||||
, addons = "Addons"
|
||||
, includedAddons = "Included addons"
|
||||
, add = "Ajouter"
|
||||
, readMore = "Read more"
|
||||
, readLess = "Read less"
|
||||
, arguments = "Arguments"
|
||||
, update = "Update"
|
||||
, argumentsUpdated = "Arguments updated"
|
||||
, configureTitle = "Configure this addon"
|
||||
, configureLabel = "Configure"
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Messages.Comp.AddonRunConfigManage exposing
|
||||
( Texts
|
||||
, de
|
||||
, fr
|
||||
, gb
|
||||
)
|
||||
|
||||
import Data.TimeZone exposing (TimeZone)
|
||||
import Http
|
||||
import Messages.Basics
|
||||
import Messages.Comp.AddonRunConfigForm
|
||||
import Messages.Comp.AddonRunConfigTable
|
||||
import Messages.Comp.HttpError
|
||||
|
||||
|
||||
type alias Texts =
|
||||
{ basics : Messages.Basics.Texts
|
||||
, addonArchiveTable : Messages.Comp.AddonRunConfigTable.Texts
|
||||
, addonArchiveForm : Messages.Comp.AddonRunConfigForm.Texts
|
||||
, httpError : Http.Error -> String
|
||||
, newAddonRunConfig : String
|
||||
, reallyDeleteAddonRunConfig : String
|
||||
, createNewAddonRunConfig : String
|
||||
, deleteThisAddonRunConfig : String
|
||||
, correctFormErrors : String
|
||||
}
|
||||
|
||||
|
||||
gb : TimeZone -> Texts
|
||||
gb tz =
|
||||
{ basics = Messages.Basics.gb
|
||||
, addonArchiveTable = Messages.Comp.AddonRunConfigTable.gb
|
||||
, addonArchiveForm = Messages.Comp.AddonRunConfigForm.gb tz
|
||||
, httpError = Messages.Comp.HttpError.gb
|
||||
, newAddonRunConfig = "New"
|
||||
, reallyDeleteAddonRunConfig = "Really delete this run config?"
|
||||
, createNewAddonRunConfig = "Create a new run configuration"
|
||||
, deleteThisAddonRunConfig = "Delete this run configuration"
|
||||
, correctFormErrors = "Please correct the errors in the form."
|
||||
}
|
||||
|
||||
|
||||
de : TimeZone -> Texts
|
||||
de tz =
|
||||
{ basics = Messages.Basics.de
|
||||
, addonArchiveTable = Messages.Comp.AddonRunConfigTable.de
|
||||
, addonArchiveForm = Messages.Comp.AddonRunConfigForm.de tz
|
||||
, httpError = Messages.Comp.HttpError.de
|
||||
, newAddonRunConfig = "Neu"
|
||||
, reallyDeleteAddonRunConfig = "Dieses Konfiguration wirklich entfernen?"
|
||||
, createNewAddonRunConfig = "Neue Run-Konfiguration erstellen"
|
||||
, deleteThisAddonRunConfig = "Run-Konfiguration löschen"
|
||||
, correctFormErrors = "Bitte korrigiere die Fehler im Formular."
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- TODO translate-fr
|
||||
|
||||
|
||||
fr : TimeZone -> Texts
|
||||
fr tz =
|
||||
{ basics = Messages.Basics.fr
|
||||
, addonArchiveTable = Messages.Comp.AddonRunConfigTable.fr
|
||||
, addonArchiveForm = Messages.Comp.AddonRunConfigForm.fr tz
|
||||
, httpError = Messages.Comp.HttpError.fr
|
||||
, newAddonRunConfig = "Nouveau favori"
|
||||
, reallyDeleteAddonRunConfig = "Confirmer la suppression de ce favori ?"
|
||||
, createNewAddonRunConfig = "Créer un nouveau favori"
|
||||
, deleteThisAddonRunConfig = "Supprimer ce favori"
|
||||
, correctFormErrors = "Veuillez corriger les erreurs du formulaire"
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Messages.Comp.AddonRunConfigTable exposing
|
||||
( Texts
|
||||
, de
|
||||
, fr
|
||||
, gb
|
||||
)
|
||||
|
||||
import Messages.Basics
|
||||
|
||||
|
||||
type alias Texts =
|
||||
{ basics : Messages.Basics.Texts
|
||||
, enabled : String
|
||||
, trigger : String
|
||||
}
|
||||
|
||||
|
||||
gb : Texts
|
||||
gb =
|
||||
{ basics = Messages.Basics.gb
|
||||
, enabled = "Enabled"
|
||||
, trigger = "Triggered"
|
||||
}
|
||||
|
||||
|
||||
de : Texts
|
||||
de =
|
||||
{ basics = Messages.Basics.de
|
||||
, enabled = "Aktive"
|
||||
, trigger = "Auslöser"
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- TODO translate-fr
|
||||
|
||||
|
||||
fr : Texts
|
||||
fr =
|
||||
{ basics = Messages.Basics.fr
|
||||
, enabled = "Enabled"
|
||||
, trigger = "Triggered"
|
||||
}
|
@ -20,6 +20,7 @@ import Messages.Comp.ItemDetail.AddFilesForm
|
||||
import Messages.Comp.ItemDetail.ConfirmModal
|
||||
import Messages.Comp.ItemDetail.ItemInfoHeader
|
||||
import Messages.Comp.ItemDetail.Notes
|
||||
import Messages.Comp.ItemDetail.RunAddonForm
|
||||
import Messages.Comp.ItemDetail.SingleAttachment
|
||||
import Messages.Comp.ItemLinkForm
|
||||
import Messages.Comp.ItemMail
|
||||
@ -38,6 +39,7 @@ type alias Texts =
|
||||
, detailEdit : Messages.Comp.DetailEdit.Texts
|
||||
, confirmModal : Messages.Comp.ItemDetail.ConfirmModal.Texts
|
||||
, itemLinkForm : Messages.Comp.ItemLinkForm.Texts
|
||||
, runAddonForm : Messages.Comp.ItemDetail.RunAddonForm.Texts
|
||||
, httpError : Http.Error -> String
|
||||
, key : String
|
||||
, backToSearchResults : String
|
||||
@ -64,6 +66,8 @@ type alias Texts =
|
||||
, selectItem : String
|
||||
, deselectItem : String
|
||||
, relatedItems : String
|
||||
, runAddonLabel : String
|
||||
, runAddonTitle : String
|
||||
}
|
||||
|
||||
|
||||
@ -78,6 +82,7 @@ gb tz =
|
||||
, detailEdit = Messages.Comp.DetailEdit.gb
|
||||
, confirmModal = Messages.Comp.ItemDetail.ConfirmModal.gb
|
||||
, itemLinkForm = Messages.Comp.ItemLinkForm.gb tz
|
||||
, runAddonForm = Messages.Comp.ItemDetail.RunAddonForm.gb
|
||||
, httpError = Messages.Comp.HttpError.gb
|
||||
, key = "Key"
|
||||
, backToSearchResults = "Back to search results"
|
||||
@ -104,6 +109,8 @@ gb tz =
|
||||
, selectItem = "Select this item"
|
||||
, deselectItem = "Deselect this item"
|
||||
, relatedItems = "Linked items"
|
||||
, runAddonLabel = "Run addon"
|
||||
, runAddonTitle = "Run an addon on this item"
|
||||
}
|
||||
|
||||
|
||||
@ -118,6 +125,7 @@ de tz =
|
||||
, detailEdit = Messages.Comp.DetailEdit.de
|
||||
, confirmModal = Messages.Comp.ItemDetail.ConfirmModal.de
|
||||
, itemLinkForm = Messages.Comp.ItemLinkForm.de tz
|
||||
, runAddonForm = Messages.Comp.ItemDetail.RunAddonForm.de
|
||||
, httpError = Messages.Comp.HttpError.de
|
||||
, key = "Taste"
|
||||
, backToSearchResults = "Zurück zur Suche"
|
||||
@ -144,6 +152,8 @@ de tz =
|
||||
, selectItem = "Zur Auswahl hinzufügen"
|
||||
, deselectItem = "Aus Auswahl entfernen"
|
||||
, relatedItems = "Verknüpfte Dokumente"
|
||||
, runAddonLabel = "Addon ausführen"
|
||||
, runAddonTitle = "Addons für dieses Dokument ausführen"
|
||||
}
|
||||
|
||||
|
||||
@ -158,6 +168,7 @@ fr tz =
|
||||
, detailEdit = Messages.Comp.DetailEdit.fr
|
||||
, confirmModal = Messages.Comp.ItemDetail.ConfirmModal.fr
|
||||
, itemLinkForm = Messages.Comp.ItemLinkForm.fr tz
|
||||
, runAddonForm = Messages.Comp.ItemDetail.RunAddonForm.fr
|
||||
, httpError = Messages.Comp.HttpError.fr
|
||||
, key = "Clé"
|
||||
, backToSearchResults = "Retour aux résultat de recherche"
|
||||
@ -184,4 +195,10 @@ fr tz =
|
||||
, selectItem = "Sélectionner ce document"
|
||||
, deselectItem = "Désélectionner ce document"
|
||||
, relatedItems = "Documents associés"
|
||||
, runAddonLabel = "Run addon"
|
||||
, runAddonTitle = "Run an addon on this item"
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- TODO translate-fr
|
||||
|
@ -0,0 +1,49 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Messages.Comp.ItemDetail.RunAddonForm exposing (Texts, de, fr, gb)
|
||||
|
||||
import Messages.Basics
|
||||
|
||||
|
||||
type alias Texts =
|
||||
{ basics : Messages.Basics.Texts
|
||||
, runAddon : String
|
||||
, addonRunConfig : String
|
||||
, runAddonTitle : String
|
||||
}
|
||||
|
||||
|
||||
gb : Texts
|
||||
gb =
|
||||
{ basics = Messages.Basics.gb
|
||||
, runAddon = "Run an addon"
|
||||
, addonRunConfig = "Addon run configuration"
|
||||
, runAddonTitle = "Run the selected addon on this item."
|
||||
}
|
||||
|
||||
|
||||
de : Texts
|
||||
de =
|
||||
{ basics = Messages.Basics.de
|
||||
, runAddon = "Addon ausführen"
|
||||
, addonRunConfig = "Addon Konfiguration"
|
||||
, runAddonTitle = "Run the selected addon on this item."
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- TODO: translate-fr
|
||||
|
||||
|
||||
fr : Texts
|
||||
fr =
|
||||
{ basics = Messages.Basics.fr
|
||||
, runAddon = "Run an addon"
|
||||
, addonRunConfig = "Addon run configuration"
|
||||
, runAddonTitle = "Run the selected addon on this item."
|
||||
}
|
@ -14,6 +14,8 @@ module Messages.Page.ManageData exposing
|
||||
|
||||
import Data.TimeZone exposing (TimeZone)
|
||||
import Messages.Basics
|
||||
import Messages.Comp.AddonArchiveManage
|
||||
import Messages.Comp.AddonRunConfigManage
|
||||
import Messages.Comp.BookmarkManage
|
||||
import Messages.Comp.CustomFieldManage
|
||||
import Messages.Comp.EquipmentManage
|
||||
@ -32,8 +34,12 @@ type alias Texts =
|
||||
, folderManage : Messages.Comp.FolderManage.Texts
|
||||
, customFieldManage : Messages.Comp.CustomFieldManage.Texts
|
||||
, bookmarkManage : Messages.Comp.BookmarkManage.Texts
|
||||
, addonArchiveManage : Messages.Comp.AddonArchiveManage.Texts
|
||||
, addonRunConfigManage : Messages.Comp.AddonRunConfigManage.Texts
|
||||
, manageData : String
|
||||
, bookmarks : String
|
||||
, addonArchives : String
|
||||
, addonRunConfigs : String
|
||||
}
|
||||
|
||||
|
||||
@ -47,8 +53,12 @@ gb tz =
|
||||
, folderManage = Messages.Comp.FolderManage.gb tz
|
||||
, customFieldManage = Messages.Comp.CustomFieldManage.gb tz
|
||||
, bookmarkManage = Messages.Comp.BookmarkManage.gb
|
||||
, addonArchiveManage = Messages.Comp.AddonArchiveManage.gb
|
||||
, addonRunConfigManage = Messages.Comp.AddonRunConfigManage.gb tz
|
||||
, manageData = "Manage Data"
|
||||
, bookmarks = "Bookmarks"
|
||||
, addonArchives = "Addons"
|
||||
, addonRunConfigs = "Addon Run Configurations"
|
||||
}
|
||||
|
||||
|
||||
@ -62,8 +72,12 @@ de tz =
|
||||
, folderManage = Messages.Comp.FolderManage.de tz
|
||||
, customFieldManage = Messages.Comp.CustomFieldManage.de tz
|
||||
, bookmarkManage = Messages.Comp.BookmarkManage.de
|
||||
, addonArchiveManage = Messages.Comp.AddonArchiveManage.de
|
||||
, addonRunConfigManage = Messages.Comp.AddonRunConfigManage.de tz
|
||||
, manageData = "Daten verwalten"
|
||||
, bookmarks = "Bookmarks"
|
||||
, addonArchives = "Addons"
|
||||
, addonRunConfigs = "Addon Run Configurations"
|
||||
}
|
||||
|
||||
|
||||
@ -77,6 +91,10 @@ fr tz =
|
||||
, folderManage = Messages.Comp.FolderManage.fr tz
|
||||
, customFieldManage = Messages.Comp.CustomFieldManage.fr tz
|
||||
, bookmarkManage = Messages.Comp.BookmarkManage.fr
|
||||
, addonArchiveManage = Messages.Comp.AddonArchiveManage.fr
|
||||
, addonRunConfigManage = Messages.Comp.AddonRunConfigManage.fr tz
|
||||
, manageData = "Gestion des métadonnées"
|
||||
, bookmarks = "Favoris"
|
||||
, addonArchives = "Addons"
|
||||
, addonRunConfigs = "Addon Run Configurations"
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ module Page.ManageData.Data exposing
|
||||
, init
|
||||
)
|
||||
|
||||
import Comp.AddonArchiveManage
|
||||
import Comp.AddonRunConfigManage
|
||||
import Comp.BookmarkManage
|
||||
import Comp.CustomFieldManage
|
||||
import Comp.EquipmentManage
|
||||
@ -31,6 +33,8 @@ type alias Model =
|
||||
, folderManageModel : Comp.FolderManage.Model
|
||||
, fieldManageModel : Comp.CustomFieldManage.Model
|
||||
, bookmarkModel : Comp.BookmarkManage.Model
|
||||
, addonArchiveModel : Comp.AddonArchiveManage.Model
|
||||
, addonRunConfigModel : Comp.AddonRunConfigManage.Model
|
||||
}
|
||||
|
||||
|
||||
@ -42,6 +46,12 @@ init flags =
|
||||
|
||||
( bm, bc ) =
|
||||
Comp.BookmarkManage.init flags
|
||||
|
||||
( aam, aac ) =
|
||||
Comp.AddonArchiveManage.init flags
|
||||
|
||||
( arm, arc ) =
|
||||
Comp.AddonRunConfigManage.init flags
|
||||
in
|
||||
( { currentTab = Just TagTab
|
||||
, tagManageModel = m2
|
||||
@ -51,10 +61,14 @@ init flags =
|
||||
, folderManageModel = Comp.FolderManage.empty
|
||||
, fieldManageModel = Comp.CustomFieldManage.empty
|
||||
, bookmarkModel = bm
|
||||
, addonArchiveModel = aam
|
||||
, addonRunConfigModel = arm
|
||||
}
|
||||
, Cmd.batch
|
||||
[ Cmd.map TagManageMsg c2
|
||||
, Cmd.map BookmarkMsg bc
|
||||
, Cmd.map AddonArchiveMsg aac
|
||||
, Cmd.map AddonRunConfigMsg arc
|
||||
]
|
||||
)
|
||||
|
||||
@ -67,6 +81,8 @@ type Tab
|
||||
| FolderTab
|
||||
| CustomFieldTab
|
||||
| BookmarkTab
|
||||
| AddonArchiveTab
|
||||
| AddonRunConfigTab
|
||||
|
||||
|
||||
type Msg
|
||||
@ -78,3 +94,5 @@ type Msg
|
||||
| FolderMsg Comp.FolderManage.Msg
|
||||
| CustomFieldMsg Comp.CustomFieldManage.Msg
|
||||
| BookmarkMsg Comp.BookmarkManage.Msg
|
||||
| AddonArchiveMsg Comp.AddonArchiveManage.Msg
|
||||
| AddonRunConfigMsg Comp.AddonRunConfigManage.Msg
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
module Page.ManageData.Update exposing (update)
|
||||
|
||||
import Comp.AddonArchiveManage
|
||||
import Comp.AddonRunConfigManage
|
||||
import Comp.BookmarkManage
|
||||
import Comp.CustomFieldManage
|
||||
import Comp.EquipmentManage
|
||||
@ -15,11 +17,12 @@ import Comp.OrgManage
|
||||
import Comp.PersonManage
|
||||
import Comp.TagManage
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Page.ManageData.Data exposing (..)
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
||||
update flags msg model =
|
||||
update : Flags -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
||||
update flags uiSettings msg model =
|
||||
case msg of
|
||||
SetTab t ->
|
||||
let
|
||||
@ -28,16 +31,16 @@ update flags msg model =
|
||||
in
|
||||
case t of
|
||||
TagTab ->
|
||||
update flags (TagManageMsg Comp.TagManage.LoadTags) m
|
||||
update flags uiSettings (TagManageMsg Comp.TagManage.LoadTags) m
|
||||
|
||||
EquipTab ->
|
||||
update flags (EquipManageMsg Comp.EquipmentManage.LoadEquipments) m
|
||||
update flags uiSettings (EquipManageMsg Comp.EquipmentManage.LoadEquipments) m
|
||||
|
||||
OrgTab ->
|
||||
update flags (OrgManageMsg Comp.OrgManage.LoadOrgs) m
|
||||
update flags uiSettings (OrgManageMsg Comp.OrgManage.LoadOrgs) m
|
||||
|
||||
PersonTab ->
|
||||
update flags (PersonManageMsg Comp.PersonManage.LoadPersons) m
|
||||
update flags uiSettings (PersonManageMsg Comp.PersonManage.LoadPersons) m
|
||||
|
||||
FolderTab ->
|
||||
let
|
||||
@ -60,6 +63,20 @@ update flags msg model =
|
||||
in
|
||||
( { m | bookmarkModel = bm }, Cmd.map BookmarkMsg bc, Sub.none )
|
||||
|
||||
AddonArchiveTab ->
|
||||
let
|
||||
( aam, aac ) =
|
||||
Comp.AddonArchiveManage.init flags
|
||||
in
|
||||
( { m | addonArchiveModel = aam }, Cmd.map AddonArchiveMsg aac, Sub.none )
|
||||
|
||||
AddonRunConfigTab ->
|
||||
let
|
||||
( arm, arc ) =
|
||||
Comp.AddonRunConfigManage.init flags
|
||||
in
|
||||
( { m | addonRunConfigModel = arm }, Cmd.map AddonRunConfigMsg arc, Sub.none )
|
||||
|
||||
TagManageMsg m ->
|
||||
let
|
||||
( m2, c2 ) =
|
||||
@ -117,3 +134,23 @@ update flags msg model =
|
||||
, Cmd.map BookmarkMsg c2
|
||||
, Sub.map BookmarkMsg s2
|
||||
)
|
||||
|
||||
AddonArchiveMsg lm ->
|
||||
let
|
||||
( aam, aac, aas ) =
|
||||
Comp.AddonArchiveManage.update flags lm model.addonArchiveModel
|
||||
in
|
||||
( { model | addonArchiveModel = aam }
|
||||
, Cmd.map AddonArchiveMsg aac
|
||||
, Sub.map AddonArchiveMsg aas
|
||||
)
|
||||
|
||||
AddonRunConfigMsg lm ->
|
||||
let
|
||||
( arm, arc, ars ) =
|
||||
Comp.AddonRunConfigManage.update flags uiSettings.timeZone lm model.addonRunConfigModel
|
||||
in
|
||||
( { model | addonRunConfigModel = arm }
|
||||
, Cmd.map AddonRunConfigMsg arc
|
||||
, Sub.map AddonRunConfigMsg ars
|
||||
)
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
module Page.ManageData.View2 exposing (viewContent, viewSidebar)
|
||||
|
||||
import Comp.AddonArchiveManage
|
||||
import Comp.AddonRunConfigManage
|
||||
import Comp.BookmarkManage
|
||||
import Comp.CustomFieldManage
|
||||
import Comp.EquipmentManage
|
||||
@ -27,7 +29,7 @@ import Styles as S
|
||||
|
||||
|
||||
viewSidebar : Texts -> Bool -> Flags -> UiSettings -> Model -> Html Msg
|
||||
viewSidebar texts visible _ settings model =
|
||||
viewSidebar texts visible flags settings model =
|
||||
div
|
||||
[ id "sidebar"
|
||||
, class S.sidebar
|
||||
@ -134,6 +136,32 @@ viewSidebar texts visible _ settings model =
|
||||
[ text texts.bookmarks
|
||||
]
|
||||
]
|
||||
, a
|
||||
[ href "#"
|
||||
, onClick (SetTab AddonArchiveTab)
|
||||
, menuEntryActive model AddonArchiveTab
|
||||
, class S.sidebarLink
|
||||
, classList [ ( "hidden", not flags.config.addonsEnabled ) ]
|
||||
]
|
||||
[ Icons.addonIcon ""
|
||||
, span
|
||||
[ class "ml-3" ]
|
||||
[ text texts.addonArchives
|
||||
]
|
||||
]
|
||||
, a
|
||||
[ href "#"
|
||||
, onClick (SetTab AddonRunConfigTab)
|
||||
, menuEntryActive model AddonRunConfigTab
|
||||
, class S.sidebarLink
|
||||
, classList [ ( "hidden", not flags.config.addonsEnabled ) ]
|
||||
]
|
||||
[ Icons.addonRunConfigIcon ""
|
||||
, span
|
||||
[ class "ml-3" ]
|
||||
[ text texts.addonRunConfigs
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
@ -166,6 +194,20 @@ viewContent texts flags settings model =
|
||||
Just BookmarkTab ->
|
||||
viewBookmarks texts flags settings model
|
||||
|
||||
Just AddonArchiveTab ->
|
||||
if flags.config.addonsEnabled then
|
||||
viewAddonArchives texts flags settings model
|
||||
|
||||
else
|
||||
[]
|
||||
|
||||
Just AddonRunConfigTab ->
|
||||
if flags.config.addonsEnabled then
|
||||
viewAddonRunConfigs texts flags settings model
|
||||
|
||||
else
|
||||
[]
|
||||
|
||||
Nothing ->
|
||||
[]
|
||||
)
|
||||
@ -306,3 +348,33 @@ viewBookmarks texts flags settings model =
|
||||
]
|
||||
, Html.map BookmarkMsg (Comp.BookmarkManage.view texts.bookmarkManage settings flags model.bookmarkModel)
|
||||
]
|
||||
|
||||
|
||||
viewAddonArchives : Texts -> Flags -> UiSettings -> Model -> List (Html Msg)
|
||||
viewAddonArchives texts flags settings model =
|
||||
[ h2
|
||||
[ class S.header1
|
||||
, class "inline-flex items-center"
|
||||
]
|
||||
[ Icons.addonIcon ""
|
||||
, div [ class "ml-2" ]
|
||||
[ text texts.addonArchives
|
||||
]
|
||||
]
|
||||
, Html.map AddonArchiveMsg (Comp.AddonArchiveManage.view texts.addonArchiveManage settings flags model.addonArchiveModel)
|
||||
]
|
||||
|
||||
|
||||
viewAddonRunConfigs : Texts -> Flags -> UiSettings -> Model -> List (Html Msg)
|
||||
viewAddonRunConfigs texts flags settings model =
|
||||
[ h2
|
||||
[ class S.header1
|
||||
, class "inline-flex items-center"
|
||||
]
|
||||
[ Icons.addonRunConfigIcon "mr-4"
|
||||
, div [ class "ml-2" ]
|
||||
[ text texts.addonRunConfigs
|
||||
]
|
||||
]
|
||||
, Html.map AddonRunConfigMsg (Comp.AddonRunConfigManage.view texts.addonRunConfigManage settings flags model.addonRunConfigModel)
|
||||
]
|
||||
|
@ -35,6 +35,11 @@ sidebarLink =
|
||||
" mb-2 px-4 py-3 flex flex-row hover:bg-blue-100 dark:hover:bg-slate-600 hover:font-bold rounded rounded-lg items-center "
|
||||
|
||||
|
||||
successText : String
|
||||
successText =
|
||||
" text-green-600 dark:text-lime-500 "
|
||||
|
||||
|
||||
successMessage : String
|
||||
successMessage =
|
||||
" border border-green-600 bg-green-50 text-green-600 dark:border-lime-800 dark:bg-lime-300 dark:text-lime-800 px-4 py-2 rounded "
|
||||
@ -281,7 +286,7 @@ link =
|
||||
|
||||
inputErrorBorder : String
|
||||
inputErrorBorder =
|
||||
" border-red-600 dark:border-orange-600 "
|
||||
" ring dark:ring-0 ring-red-600 dark:border-orange-600 "
|
||||
|
||||
|
||||
inputLabel : String
|
||||
|
@ -14,12 +14,42 @@ module Util.List exposing
|
||||
, findNext
|
||||
, findPrev
|
||||
, get
|
||||
, removeByIndex
|
||||
, replaceByIndex
|
||||
, sliding
|
||||
)
|
||||
|
||||
import Html.Attributes exposing (list)
|
||||
|
||||
|
||||
removeByIndex : Int -> List a -> List a
|
||||
removeByIndex index list =
|
||||
List.indexedMap
|
||||
(\idx ->
|
||||
\e ->
|
||||
if idx == index then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just e
|
||||
)
|
||||
list
|
||||
|> List.filterMap identity
|
||||
|
||||
|
||||
replaceByIndex : Int -> a -> List a -> List a
|
||||
replaceByIndex index element list =
|
||||
let
|
||||
repl idx e =
|
||||
if idx == index then
|
||||
element
|
||||
|
||||
else
|
||||
e
|
||||
in
|
||||
List.indexedMap repl list
|
||||
|
||||
|
||||
changePosition : Int -> Int -> List a -> List a
|
||||
changePosition source target list =
|
||||
let
|
||||
|
@ -9,6 +9,7 @@ module Util.String exposing
|
||||
( appendIfAbsent
|
||||
, crazyEncode
|
||||
, ellipsis
|
||||
, firstSentenceOrMax
|
||||
, isBlank
|
||||
, isNothingOrBlank
|
||||
, underscoreToSpace
|
||||
@ -16,7 +17,6 @@ module Util.String exposing
|
||||
)
|
||||
|
||||
import Base64
|
||||
import Html exposing (strong)
|
||||
|
||||
|
||||
crazyEncode : String -> String
|
||||
@ -45,6 +45,26 @@ ellipsis len str =
|
||||
String.left (len - 1) str ++ "…"
|
||||
|
||||
|
||||
firstSentenceOrMax : Int -> String -> Maybe String
|
||||
firstSentenceOrMax maxLen str =
|
||||
let
|
||||
idx =
|
||||
String.indexes "." str
|
||||
|> List.head
|
||||
|> Maybe.map ((+) 2)
|
||||
|> Maybe.map (min maxLen)
|
||||
|> Maybe.withDefault maxLen
|
||||
|
||||
len =
|
||||
String.length str
|
||||
in
|
||||
if len <= maxLen then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just <| String.left (idx - 1) str ++ "…"
|
||||
|
||||
|
||||
withDefault : String -> String -> String
|
||||
withDefault default str =
|
||||
if str == "" then
|
||||
|
@ -96,4 +96,8 @@
|
||||
.markdown-preview a {
|
||||
@apply text-blue-400 hover:text-blue-500 dark:text-sky-200 dark:hover:text-sky-100 cursor-pointer;
|
||||
}
|
||||
|
||||
.markdown-preview pre {
|
||||
@apply font-mono px-2 py-2 text-sm border dark:border-slate-600 rounded my-2;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user