mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-22 18:38:26 +00:00
Basic management of shares
This commit is contained in:
@ -11,6 +11,7 @@ module Api exposing
|
||||
, addCorrOrg
|
||||
, addCorrPerson
|
||||
, addMember
|
||||
, addShare
|
||||
, addTag
|
||||
, addTagsMultiple
|
||||
, attachmentPreviewURL
|
||||
@ -40,6 +41,7 @@ module Api exposing
|
||||
, deleteOrg
|
||||
, deletePerson
|
||||
, deleteScanMailbox
|
||||
, deleteShare
|
||||
, deleteSource
|
||||
, deleteTag
|
||||
, deleteUser
|
||||
@ -72,6 +74,8 @@ module Api exposing
|
||||
, getPersonsLight
|
||||
, getScanMailbox
|
||||
, getSentMails
|
||||
, getShare
|
||||
, getShares
|
||||
, getSources
|
||||
, getTagCloud
|
||||
, getTags
|
||||
@ -147,6 +151,7 @@ module Api exposing
|
||||
, unconfirmMultiple
|
||||
, updateNotifyDueItems
|
||||
, updateScanMailbox
|
||||
, updateShare
|
||||
, upload
|
||||
, uploadAmend
|
||||
, uploadSingle
|
||||
@ -215,6 +220,9 @@ import Api.Model.ScanMailboxSettingsList exposing (ScanMailboxSettingsList)
|
||||
import Api.Model.SearchStats exposing (SearchStats)
|
||||
import Api.Model.SecondFactor exposing (SecondFactor)
|
||||
import Api.Model.SentMails exposing (SentMails)
|
||||
import Api.Model.ShareData exposing (ShareData)
|
||||
import Api.Model.ShareDetail exposing (ShareDetail)
|
||||
import Api.Model.ShareList exposing (ShareList)
|
||||
import Api.Model.SimpleMail exposing (SimpleMail)
|
||||
import Api.Model.SourceAndTags exposing (SourceAndTags)
|
||||
import Api.Model.SourceList exposing (SourceList)
|
||||
@ -2206,6 +2214,57 @@ disableOtp flags otp receive =
|
||||
|
||||
|
||||
|
||||
--- Share
|
||||
|
||||
|
||||
getShares : Flags -> (Result Http.Error ShareList -> msg) -> Cmd msg
|
||||
getShares flags receive =
|
||||
Http2.authGet
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/share"
|
||||
, account = getAccount flags
|
||||
, expect = Http.expectJson receive Api.Model.ShareList.decoder
|
||||
}
|
||||
|
||||
|
||||
getShare : Flags -> String -> (Result Http.Error ShareDetail -> msg) -> Cmd msg
|
||||
getShare flags id receive =
|
||||
Http2.authGet
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/share/" ++ id
|
||||
, account = getAccount flags
|
||||
, expect = Http.expectJson receive Api.Model.ShareDetail.decoder
|
||||
}
|
||||
|
||||
|
||||
addShare : Flags -> ShareData -> (Result Http.Error IdResult -> msg) -> Cmd msg
|
||||
addShare flags share receive =
|
||||
Http2.authPost
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/share"
|
||||
, account = getAccount flags
|
||||
, body = Http.jsonBody (Api.Model.ShareData.encode share)
|
||||
, expect = Http.expectJson receive Api.Model.IdResult.decoder
|
||||
}
|
||||
|
||||
|
||||
updateShare : Flags -> String -> ShareData -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
updateShare flags id share receive =
|
||||
Http2.authPut
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/share/" ++ id
|
||||
, account = getAccount flags
|
||||
, body = Http.jsonBody (Api.Model.ShareData.encode share)
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
deleteShare : Flags -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
deleteShare flags id receive =
|
||||
Http2.authDelete
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/share/" ++ id
|
||||
, account = getAccount flags
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Helper
|
||||
|
||||
|
||||
|
@ -37,7 +37,7 @@ init =
|
||||
|
||||
emptyModel : DatePicker
|
||||
emptyModel =
|
||||
DatePicker.initFromDate (Date.fromCalendarDate 2019 Aug 21)
|
||||
DatePicker.initFromDate (Date.fromCalendarDate 2021 Oct 31)
|
||||
|
||||
|
||||
defaultSettings : Settings
|
||||
|
282
modules/webapp/src/main/elm/Comp/ShareForm.elm
Normal file
282
modules/webapp/src/main/elm/Comp/ShareForm.elm
Normal file
@ -0,0 +1,282 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.ShareForm exposing (Model, Msg, getShare, init, setShare, update, view)
|
||||
|
||||
import Api.Model.ShareData exposing (ShareData)
|
||||
import Api.Model.ShareDetail exposing (ShareDetail)
|
||||
import Comp.Basic as B
|
||||
import Comp.DatePicker
|
||||
import Comp.PasswordInput
|
||||
import Data.Flags exposing (Flags)
|
||||
import DatePicker exposing (DatePicker)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onCheck, onInput)
|
||||
import Messages.Comp.ShareForm exposing (Texts)
|
||||
import Styles as S
|
||||
import Util.Maybe
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ share : ShareDetail
|
||||
, name : Maybe String
|
||||
, query : String
|
||||
, enabled : Bool
|
||||
, passwordModel : Comp.PasswordInput.Model
|
||||
, password : Maybe String
|
||||
, passwordSet : Bool
|
||||
, clearPassword : Bool
|
||||
, untilModel : DatePicker
|
||||
, untilDate : Maybe Int
|
||||
}
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
let
|
||||
( dp, dpc ) =
|
||||
Comp.DatePicker.init
|
||||
in
|
||||
( { share = Api.Model.ShareDetail.empty
|
||||
, name = Nothing
|
||||
, query = ""
|
||||
, enabled = False
|
||||
, passwordModel = Comp.PasswordInput.init
|
||||
, password = Nothing
|
||||
, passwordSet = False
|
||||
, clearPassword = False
|
||||
, untilModel = dp
|
||||
, untilDate = Nothing
|
||||
}
|
||||
, Cmd.map UntilDateMsg dpc
|
||||
)
|
||||
|
||||
|
||||
isValid : Model -> Bool
|
||||
isValid model =
|
||||
model.query /= "" && model.untilDate /= Nothing
|
||||
|
||||
|
||||
type Msg
|
||||
= SetName String
|
||||
| SetQuery String
|
||||
| SetShare ShareDetail
|
||||
| ToggleEnabled
|
||||
| ToggleClearPassword
|
||||
| PasswordMsg Comp.PasswordInput.Msg
|
||||
| UntilDateMsg Comp.DatePicker.Msg
|
||||
|
||||
|
||||
setShare : ShareDetail -> Msg
|
||||
setShare share =
|
||||
SetShare share
|
||||
|
||||
|
||||
getShare : Model -> Maybe ( String, ShareData )
|
||||
getShare model =
|
||||
if isValid model then
|
||||
Just
|
||||
( model.share.id
|
||||
, { name = model.name
|
||||
, query = model.query
|
||||
, enabled = model.enabled
|
||||
, password = model.password
|
||||
, removePassword =
|
||||
if model.share.id == "" then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just model.clearPassword
|
||||
, publishUntil = Maybe.withDefault 0 model.untilDate
|
||||
}
|
||||
)
|
||||
|
||||
else
|
||||
Nothing
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update _ msg model =
|
||||
case msg of
|
||||
SetShare s ->
|
||||
( { model
|
||||
| share = s
|
||||
, name = s.name
|
||||
, query = s.query
|
||||
, enabled = s.enabled
|
||||
, password = Nothing
|
||||
, passwordSet = s.password
|
||||
, clearPassword = False
|
||||
, untilDate =
|
||||
if s.publishUntil > 0 then
|
||||
Just s.publishUntil
|
||||
|
||||
else
|
||||
Nothing
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
SetName n ->
|
||||
( { model | name = Util.Maybe.fromString n }, Cmd.none )
|
||||
|
||||
SetQuery n ->
|
||||
( { model | query = n }, Cmd.none )
|
||||
|
||||
ToggleEnabled ->
|
||||
( { model | enabled = not model.enabled }, Cmd.none )
|
||||
|
||||
ToggleClearPassword ->
|
||||
( { model | clearPassword = not model.clearPassword }, Cmd.none )
|
||||
|
||||
PasswordMsg lm ->
|
||||
let
|
||||
( pm, pw ) =
|
||||
Comp.PasswordInput.update lm model.passwordModel
|
||||
in
|
||||
( { model
|
||||
| passwordModel = pm
|
||||
, password = pw
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
UntilDateMsg lm ->
|
||||
let
|
||||
( dp, event ) =
|
||||
Comp.DatePicker.updateDefault lm model.untilModel
|
||||
|
||||
nextDate =
|
||||
case event of
|
||||
DatePicker.Picked date ->
|
||||
Just (Comp.DatePicker.endOfDay date)
|
||||
|
||||
_ ->
|
||||
Nothing
|
||||
in
|
||||
( { model | untilModel = dp, untilDate = nextDate }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
--- View
|
||||
|
||||
|
||||
view : Texts -> Model -> Html Msg
|
||||
view texts model =
|
||||
div
|
||||
[ class "flex flex-col" ]
|
||||
[ div [ class "mb-4" ]
|
||||
[ label
|
||||
[ for "sharename"
|
||||
, class S.inputLabel
|
||||
]
|
||||
[ text texts.basics.name
|
||||
]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetName
|
||||
, placeholder texts.basics.name
|
||||
, value <| Maybe.withDefault "" model.name
|
||||
, id "sharename"
|
||||
, class S.textInput
|
||||
]
|
||||
[]
|
||||
]
|
||||
, div [ class "mb-4" ]
|
||||
[ label
|
||||
[ for "sharequery"
|
||||
, class S.inputLabel
|
||||
]
|
||||
[ text texts.queryLabel
|
||||
, B.inputRequired
|
||||
]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetQuery
|
||||
, placeholder texts.queryLabel
|
||||
, value model.query
|
||||
, id "sharequery"
|
||||
, class S.textInput
|
||||
, classList
|
||||
[ ( S.inputErrorBorder
|
||||
, not (isValid model)
|
||||
)
|
||||
]
|
||||
]
|
||||
[]
|
||||
]
|
||||
, div [ class "mb-4" ]
|
||||
[ label
|
||||
[ class "inline-flex items-center"
|
||||
, for "source-enabled"
|
||||
]
|
||||
[ input
|
||||
[ type_ "checkbox"
|
||||
, onCheck (\_ -> ToggleEnabled)
|
||||
, checked model.enabled
|
||||
, class S.checkboxInput
|
||||
, id "source-enabled"
|
||||
]
|
||||
[]
|
||||
, span [ class "ml-2" ]
|
||||
[ text texts.enabled
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "mb-4" ]
|
||||
[ label
|
||||
[ class S.inputLabel
|
||||
]
|
||||
[ text texts.password
|
||||
]
|
||||
, Html.map PasswordMsg
|
||||
(Comp.PasswordInput.view2
|
||||
{ placeholder = texts.password }
|
||||
model.password
|
||||
False
|
||||
model.passwordModel
|
||||
)
|
||||
, div
|
||||
[ class "mb-2"
|
||||
, classList [ ( "hidden", not model.passwordSet ) ]
|
||||
]
|
||||
[ label
|
||||
[ class "inline-flex items-center"
|
||||
, for "clear-password"
|
||||
]
|
||||
[ input
|
||||
[ type_ "checkbox"
|
||||
, onCheck (\_ -> ToggleClearPassword)
|
||||
, checked model.clearPassword
|
||||
, class S.checkboxInput
|
||||
, id "clear-password"
|
||||
]
|
||||
[]
|
||||
, span [ class "ml-2" ]
|
||||
[ text texts.clearPassword
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "mb-2 max-w-sm" ]
|
||||
[ label [ class S.inputLabel ]
|
||||
[ text texts.publishUntil
|
||||
, B.inputRequired
|
||||
]
|
||||
, div [ class "relative" ]
|
||||
[ Html.map UntilDateMsg
|
||||
(Comp.DatePicker.viewTimeDefault
|
||||
model.untilDate
|
||||
model.untilModel
|
||||
)
|
||||
, i [ class S.dateInputIcon, class "fa fa-calendar" ] []
|
||||
]
|
||||
]
|
||||
]
|
349
modules/webapp/src/main/elm/Comp/ShareManage.elm
Normal file
349
modules/webapp/src/main/elm/Comp/ShareManage.elm
Normal file
@ -0,0 +1,349 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.ShareManage exposing (Model, Msg, init, loadShares, update, view)
|
||||
|
||||
import Api
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.IdResult exposing (IdResult)
|
||||
import Api.Model.ShareDetail exposing (ShareDetail)
|
||||
import Api.Model.ShareList exposing (ShareList)
|
||||
import Comp.Basic as B
|
||||
import Comp.ItemDetail.Model exposing (Msg(..))
|
||||
import Comp.MenuBar as MB
|
||||
import Comp.ShareForm
|
||||
import Comp.ShareTable
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Http
|
||||
import Messages.Comp.ShareManage exposing (Texts)
|
||||
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
|
||||
, shares : List ShareDetail
|
||||
, formModel : Comp.ShareForm.Model
|
||||
, loading : Bool
|
||||
, formError : FormError
|
||||
, deleteConfirm : DeleteConfirm
|
||||
}
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
let
|
||||
( fm, fc ) =
|
||||
Comp.ShareForm.init
|
||||
in
|
||||
( { viewMode = Table
|
||||
, shares = []
|
||||
, formModel = fm
|
||||
, loading = False
|
||||
, formError = FormErrorNone
|
||||
, deleteConfirm = DeleteConfirmOff
|
||||
}
|
||||
, Cmd.map FormMsg fc
|
||||
)
|
||||
|
||||
|
||||
type Msg
|
||||
= LoadShares
|
||||
| TableMsg Comp.ShareTable.Msg
|
||||
| FormMsg Comp.ShareForm.Msg
|
||||
| InitNewShare
|
||||
| SetViewMode ViewMode
|
||||
| Submit
|
||||
| RequestDelete
|
||||
| CancelDelete
|
||||
| DeleteShareNow String
|
||||
| LoadSharesResp (Result Http.Error ShareList)
|
||||
| AddShareResp (Result Http.Error IdResult)
|
||||
| UpdateShareResp (Result Http.Error BasicResult)
|
||||
| GetShareResp (Result Http.Error ShareDetail)
|
||||
| DeleteShareResp (Result Http.Error BasicResult)
|
||||
|
||||
|
||||
loadShares : Msg
|
||||
loadShares =
|
||||
LoadShares
|
||||
|
||||
|
||||
|
||||
--- update
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
InitNewShare ->
|
||||
let
|
||||
nm =
|
||||
{ model | viewMode = Form, formError = FormErrorNone }
|
||||
|
||||
share =
|
||||
Api.Model.ShareDetail.empty
|
||||
in
|
||||
update flags (FormMsg (Comp.ShareForm.setShare share)) nm
|
||||
|
||||
SetViewMode vm ->
|
||||
( { model | viewMode = vm, formError = FormErrorNone }
|
||||
, if vm == Table then
|
||||
Api.getShares flags LoadSharesResp
|
||||
|
||||
else
|
||||
Cmd.none
|
||||
)
|
||||
|
||||
FormMsg lm ->
|
||||
let
|
||||
( fm, fc ) =
|
||||
Comp.ShareForm.update flags lm model.formModel
|
||||
in
|
||||
( { model | formModel = fm }, Cmd.map FormMsg fc )
|
||||
|
||||
TableMsg lm ->
|
||||
let
|
||||
action =
|
||||
Comp.ShareTable.update lm
|
||||
|
||||
nextModel =
|
||||
{ model | viewMode = Form, formError = FormErrorNone }
|
||||
in
|
||||
case action of
|
||||
Comp.ShareTable.Edit share ->
|
||||
update flags (FormMsg <| Comp.ShareForm.setShare share) nextModel
|
||||
|
||||
RequestDelete ->
|
||||
( { model | deleteConfirm = DeleteConfirmOn }, Cmd.none )
|
||||
|
||||
CancelDelete ->
|
||||
( { model | deleteConfirm = DeleteConfirmOff }, Cmd.none )
|
||||
|
||||
DeleteShareNow id ->
|
||||
( { model | deleteConfirm = DeleteConfirmOff, loading = True }
|
||||
, Api.deleteShare flags id DeleteShareResp
|
||||
)
|
||||
|
||||
LoadShares ->
|
||||
( { model | loading = True }, Api.getShares flags LoadSharesResp )
|
||||
|
||||
LoadSharesResp (Ok list) ->
|
||||
( { model | loading = False, shares = list.items, formError = FormErrorNone }, Cmd.none )
|
||||
|
||||
LoadSharesResp (Err err) ->
|
||||
( { model | loading = False, formError = FormErrorHttp err }, Cmd.none )
|
||||
|
||||
Submit ->
|
||||
case Comp.ShareForm.getShare model.formModel of
|
||||
Just ( id, data ) ->
|
||||
if id == "" then
|
||||
( { model | loading = True }, Api.addShare flags data AddShareResp )
|
||||
|
||||
else
|
||||
( { model | loading = True }, Api.updateShare flags id data UpdateShareResp )
|
||||
|
||||
Nothing ->
|
||||
( { model | formError = FormErrorInvalid }, Cmd.none )
|
||||
|
||||
AddShareResp (Ok res) ->
|
||||
if res.success then
|
||||
( model, Api.getShare flags res.id GetShareResp )
|
||||
|
||||
else
|
||||
( { model | loading = False, formError = FormErrorSubmit res.message }, Cmd.none )
|
||||
|
||||
AddShareResp (Err err) ->
|
||||
( { model | loading = False, formError = FormErrorHttp err }, Cmd.none )
|
||||
|
||||
UpdateShareResp (Ok res) ->
|
||||
if res.success then
|
||||
( model, Api.getShare flags model.formModel.share.id GetShareResp )
|
||||
|
||||
else
|
||||
( { model | loading = False, formError = FormErrorSubmit res.message }, Cmd.none )
|
||||
|
||||
UpdateShareResp (Err err) ->
|
||||
( { model | loading = False, formError = FormErrorHttp err }, Cmd.none )
|
||||
|
||||
GetShareResp (Ok share) ->
|
||||
let
|
||||
nextModel =
|
||||
{ model | formError = FormErrorNone, loading = False }
|
||||
in
|
||||
update flags (FormMsg <| Comp.ShareForm.setShare share) nextModel
|
||||
|
||||
GetShareResp (Err err) ->
|
||||
( { model | formError = FormErrorHttp err }, Cmd.none )
|
||||
|
||||
DeleteShareResp (Ok res) ->
|
||||
if res.success then
|
||||
update flags (SetViewMode Table) { model | loading = False }
|
||||
|
||||
else
|
||||
( { model | formError = FormErrorSubmit res.message, loading = False }, Cmd.none )
|
||||
|
||||
DeleteShareResp (Err err) ->
|
||||
( { model | formError = FormErrorHttp err, loading = False }, Cmd.none )
|
||||
|
||||
|
||||
|
||||
--- view
|
||||
|
||||
|
||||
view : Texts -> Flags -> Model -> Html Msg
|
||||
view texts _ model =
|
||||
if model.viewMode == Table then
|
||||
viewTable texts model
|
||||
|
||||
else
|
||||
viewForm texts model
|
||||
|
||||
|
||||
viewTable : Texts -> Model -> Html Msg
|
||||
viewTable texts model =
|
||||
div [ class "flex flex-col" ]
|
||||
[ MB.view
|
||||
{ start =
|
||||
[]
|
||||
, end =
|
||||
[ MB.PrimaryButton
|
||||
{ tagger = InitNewShare
|
||||
, title = texts.createNewShare
|
||||
, icon = Just "fa fa-plus"
|
||||
, label = texts.newShare
|
||||
}
|
||||
]
|
||||
, rootClasses = "mb-4"
|
||||
}
|
||||
, Html.map TableMsg (Comp.ShareTable.view texts.shareTable model.shares)
|
||||
, B.loadingDimmer
|
||||
{ label = ""
|
||||
, active = model.loading
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
viewForm : Texts -> Model -> Html Msg
|
||||
viewForm texts model =
|
||||
let
|
||||
newShare =
|
||||
model.formModel.share.id == ""
|
||||
in
|
||||
Html.form [ class "relative" ]
|
||||
[ if newShare then
|
||||
h1 [ class S.header2 ]
|
||||
[ text texts.createNewShare
|
||||
]
|
||||
|
||||
else
|
||||
h1 [ class S.header2 ]
|
||||
[ text <| Maybe.withDefault texts.noName model.formModel.share.name
|
||||
, div [ class "opacity-50 text-sm" ]
|
||||
[ text "Id: "
|
||||
, text model.formModel.share.id
|
||||
]
|
||||
]
|
||||
, MB.view
|
||||
{ start =
|
||||
[ MB.PrimaryButton
|
||||
{ tagger = Submit
|
||||
, title = "Submit this form"
|
||||
, icon = Just "fa fa-save"
|
||||
, label = texts.basics.submit
|
||||
}
|
||||
, MB.SecondaryButton
|
||||
{ tagger = SetViewMode Table
|
||||
, title = texts.basics.backToList
|
||||
, icon = Just "fa fa-arrow-left"
|
||||
, label = texts.basics.cancel
|
||||
}
|
||||
]
|
||||
, end =
|
||||
if not newShare then
|
||||
[ MB.DeleteButton
|
||||
{ tagger = RequestDelete
|
||||
, title = texts.deleteThisShare
|
||||
, icon = Just "fa fa-trash"
|
||||
, label = texts.basics.delete
|
||||
}
|
||||
]
|
||||
|
||||
else
|
||||
[]
|
||||
, rootClasses = "mb-4"
|
||||
}
|
||||
, 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
|
||||
]
|
||||
, Html.map FormMsg (Comp.ShareForm.view texts.shareForm 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.reallyDeleteShare
|
||||
]
|
||||
, div [ class "mt-4 flex flex-row items-center" ]
|
||||
[ B.deleteButton
|
||||
{ label = texts.basics.yes
|
||||
, icon = "fa fa-check"
|
||||
, disabled = False
|
||||
, handler = onClick (DeleteShareNow model.formModel.share.id)
|
||||
, attrs = [ href "#" ]
|
||||
}
|
||||
, B.secondaryButton
|
||||
{ label = texts.basics.no
|
||||
, icon = "fa fa-times"
|
||||
, disabled = False
|
||||
, handler = onClick CancelDelete
|
||||
, attrs = [ href "#", class "ml-2" ]
|
||||
}
|
||||
]
|
||||
]
|
||||
)
|
||||
]
|
87
modules/webapp/src/main/elm/Comp/ShareTable.elm
Normal file
87
modules/webapp/src/main/elm/Comp/ShareTable.elm
Normal file
@ -0,0 +1,87 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.ShareTable exposing
|
||||
( Msg(..)
|
||||
, SelectAction(..)
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.ShareDetail exposing (ShareDetail)
|
||||
import Comp.Basic as B
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Messages.Comp.ShareTable exposing (Texts)
|
||||
import Styles as S
|
||||
import Util.Html
|
||||
import Util.String
|
||||
|
||||
|
||||
type Msg
|
||||
= Select ShareDetail
|
||||
|
||||
|
||||
type SelectAction
|
||||
= Edit ShareDetail
|
||||
|
||||
|
||||
update : Msg -> SelectAction
|
||||
update msg =
|
||||
case msg of
|
||||
Select share ->
|
||||
Edit share
|
||||
|
||||
|
||||
|
||||
--- View
|
||||
|
||||
|
||||
view : Texts -> List ShareDetail -> Html Msg
|
||||
view texts shares =
|
||||
table [ class S.tableMain ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "" ] []
|
||||
, th [ class "text-left" ]
|
||||
[ text texts.basics.id
|
||||
]
|
||||
, th [ class "text-left" ]
|
||||
[ text texts.basics.name
|
||||
]
|
||||
, th [ class "text-center" ]
|
||||
[ text texts.enabled
|
||||
]
|
||||
, th [ class "text-center" ]
|
||||
[ text texts.publishUntil
|
||||
]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(List.map (renderShareLine texts) shares)
|
||||
]
|
||||
|
||||
|
||||
renderShareLine : Texts -> ShareDetail -> Html Msg
|
||||
renderShareLine texts share =
|
||||
tr
|
||||
[ class S.tableRow
|
||||
]
|
||||
[ B.editLinkTableCell texts.basics.edit (Select share)
|
||||
, td [ class "text-left py-4 md:py-2" ]
|
||||
[ text (Util.String.ellipsis 8 share.id)
|
||||
]
|
||||
, td [ class "text-left py-4 md:py-2" ]
|
||||
[ text (Maybe.withDefault "-" share.name)
|
||||
]
|
||||
, td [ class "w-px px-2 text-center" ]
|
||||
[ Util.Html.checkbox2 share.enabled
|
||||
]
|
||||
, td [ class "hidden sm:table-cell text-center" ]
|
||||
[ texts.formatDateTime share.publishUntil |> text
|
||||
]
|
||||
]
|
@ -58,11 +58,11 @@ module Data.Icons exposing
|
||||
, personIcon2
|
||||
, search
|
||||
, searchIcon
|
||||
, share
|
||||
, shareIcon
|
||||
, showQr
|
||||
, showQrIcon
|
||||
, source
|
||||
, source2
|
||||
, sourceIcon
|
||||
, sourceIcon2
|
||||
, tag
|
||||
, tag2
|
||||
@ -79,9 +79,14 @@ import Html exposing (Html, i)
|
||||
import Html.Attributes exposing (class)
|
||||
|
||||
|
||||
source : String
|
||||
source =
|
||||
"upload icon"
|
||||
share : String
|
||||
share =
|
||||
"fa fa-share-alt"
|
||||
|
||||
|
||||
shareIcon : String -> Html msg
|
||||
shareIcon classes =
|
||||
i [ class (classes ++ " " ++ share) ] []
|
||||
|
||||
|
||||
source2 : String
|
||||
@ -89,11 +94,6 @@ source2 =
|
||||
"fa fa-upload"
|
||||
|
||||
|
||||
sourceIcon : String -> Html msg
|
||||
sourceIcon classes =
|
||||
i [ class (source ++ " " ++ classes) ] []
|
||||
|
||||
|
||||
sourceIcon2 : String -> Html msg
|
||||
sourceIcon2 classes =
|
||||
i [ class (source2 ++ " " ++ classes) ] []
|
||||
|
46
modules/webapp/src/main/elm/Messages/Comp/ShareForm.elm
Normal file
46
modules/webapp/src/main/elm/Messages/Comp/ShareForm.elm
Normal file
@ -0,0 +1,46 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Messages.Comp.ShareForm exposing
|
||||
( Texts
|
||||
, de
|
||||
, gb
|
||||
)
|
||||
|
||||
import Messages.Basics
|
||||
|
||||
|
||||
type alias Texts =
|
||||
{ basics : Messages.Basics.Texts
|
||||
, queryLabel : String
|
||||
, enabled : String
|
||||
, password : String
|
||||
, publishUntil : String
|
||||
, clearPassword : String
|
||||
}
|
||||
|
||||
|
||||
gb : Texts
|
||||
gb =
|
||||
{ basics = Messages.Basics.gb
|
||||
, queryLabel = "Query"
|
||||
, enabled = "Enabled"
|
||||
, password = "Password"
|
||||
, publishUntil = "Publish Until"
|
||||
, clearPassword = "Remove password"
|
||||
}
|
||||
|
||||
|
||||
de : Texts
|
||||
de =
|
||||
{ basics = Messages.Basics.de
|
||||
, queryLabel = "Abfrage"
|
||||
, enabled = "Aktiv"
|
||||
, password = "Passwort"
|
||||
, publishUntil = "Publiziert bis"
|
||||
, clearPassword = "Passwort entfernen"
|
||||
}
|
74
modules/webapp/src/main/elm/Messages/Comp/ShareManage.elm
Normal file
74
modules/webapp/src/main/elm/Messages/Comp/ShareManage.elm
Normal file
@ -0,0 +1,74 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Messages.Comp.ShareManage exposing
|
||||
( Texts
|
||||
, de
|
||||
, gb
|
||||
)
|
||||
|
||||
import Http
|
||||
import Messages.Basics
|
||||
import Messages.Comp.HttpError
|
||||
import Messages.Comp.ShareForm
|
||||
import Messages.Comp.ShareTable
|
||||
|
||||
|
||||
type alias Texts =
|
||||
{ basics : Messages.Basics.Texts
|
||||
, shareTable : Messages.Comp.ShareTable.Texts
|
||||
, shareForm : Messages.Comp.ShareForm.Texts
|
||||
, httpError : Http.Error -> String
|
||||
, newShare : String
|
||||
, copyToClipboard : String
|
||||
, openInNewTab : String
|
||||
, publicUrl : String
|
||||
, reallyDeleteShare : String
|
||||
, createNewShare : String
|
||||
, deleteThisShare : String
|
||||
, errorGeneratingQR : String
|
||||
, correctFormErrors : String
|
||||
, noName : String
|
||||
}
|
||||
|
||||
|
||||
gb : Texts
|
||||
gb =
|
||||
{ basics = Messages.Basics.gb
|
||||
, httpError = Messages.Comp.HttpError.gb
|
||||
, shareTable = Messages.Comp.ShareTable.gb
|
||||
, shareForm = Messages.Comp.ShareForm.gb
|
||||
, newShare = "New share"
|
||||
, copyToClipboard = "Copy to clipboard"
|
||||
, openInNewTab = "Open in new tab/window"
|
||||
, publicUrl = "Public URL"
|
||||
, reallyDeleteShare = "Really delete this share?"
|
||||
, createNewShare = "Create new share"
|
||||
, deleteThisShare = "Delete this share"
|
||||
, errorGeneratingQR = "Error generating QR Code"
|
||||
, correctFormErrors = "Please correct the errors in the form."
|
||||
, noName = "No Name"
|
||||
}
|
||||
|
||||
|
||||
de : Texts
|
||||
de =
|
||||
{ basics = Messages.Basics.de
|
||||
, shareTable = Messages.Comp.ShareTable.de
|
||||
, shareForm = Messages.Comp.ShareForm.de
|
||||
, httpError = Messages.Comp.HttpError.de
|
||||
, newShare = "Neue Freigabe"
|
||||
, copyToClipboard = "In die Zwischenablage kopieren"
|
||||
, openInNewTab = "Im neuen Tab/Fenster öffnen"
|
||||
, publicUrl = "Öffentliche URL"
|
||||
, reallyDeleteShare = "Diese Freigabe wirklich entfernen?"
|
||||
, createNewShare = "Neue Freigabe erstellen"
|
||||
, deleteThisShare = "Freigabe löschen"
|
||||
, errorGeneratingQR = "Fehler beim Generieren des QR-Code"
|
||||
, correctFormErrors = "Bitte korrigiere die Fehler im Formular."
|
||||
, noName = "Ohne Name"
|
||||
}
|
42
modules/webapp/src/main/elm/Messages/Comp/ShareTable.elm
Normal file
42
modules/webapp/src/main/elm/Messages/Comp/ShareTable.elm
Normal file
@ -0,0 +1,42 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Messages.Comp.ShareTable exposing
|
||||
( Texts
|
||||
, de
|
||||
, gb
|
||||
)
|
||||
|
||||
import Messages.Basics
|
||||
import Messages.DateFormat as DF
|
||||
import Messages.UiLanguage
|
||||
|
||||
|
||||
type alias Texts =
|
||||
{ basics : Messages.Basics.Texts
|
||||
, formatDateTime : Int -> String
|
||||
, enabled : String
|
||||
, publishUntil : String
|
||||
}
|
||||
|
||||
|
||||
gb : Texts
|
||||
gb =
|
||||
{ basics = Messages.Basics.gb
|
||||
, formatDateTime = DF.formatDateTimeLong Messages.UiLanguage.English
|
||||
, enabled = "Enabled"
|
||||
, publishUntil = "Publish Until"
|
||||
}
|
||||
|
||||
|
||||
de : Texts
|
||||
de =
|
||||
{ basics = Messages.Basics.de
|
||||
, formatDateTime = DF.formatDateTimeLong Messages.UiLanguage.German
|
||||
, enabled = "Aktiv"
|
||||
, publishUntil = "Publiziert bis"
|
||||
}
|
@ -15,6 +15,7 @@ import Http
|
||||
import Messages.Basics
|
||||
import Messages.Comp.CollectiveSettingsForm
|
||||
import Messages.Comp.HttpError
|
||||
import Messages.Comp.ShareManage
|
||||
import Messages.Comp.SourceManage
|
||||
import Messages.Comp.UserManage
|
||||
|
||||
@ -24,12 +25,14 @@ type alias Texts =
|
||||
, userManage : Messages.Comp.UserManage.Texts
|
||||
, collectiveSettingsForm : Messages.Comp.CollectiveSettingsForm.Texts
|
||||
, sourceManage : Messages.Comp.SourceManage.Texts
|
||||
, shareManage : Messages.Comp.ShareManage.Texts
|
||||
, httpError : Http.Error -> String
|
||||
, collectiveSettings : String
|
||||
, insights : String
|
||||
, sources : String
|
||||
, settings : String
|
||||
, users : String
|
||||
, shares : String
|
||||
, user : String
|
||||
, collective : String
|
||||
, size : String
|
||||
@ -44,12 +47,14 @@ gb =
|
||||
, userManage = Messages.Comp.UserManage.gb
|
||||
, collectiveSettingsForm = Messages.Comp.CollectiveSettingsForm.gb
|
||||
, sourceManage = Messages.Comp.SourceManage.gb
|
||||
, shareManage = Messages.Comp.ShareManage.gb
|
||||
, httpError = Messages.Comp.HttpError.gb
|
||||
, collectiveSettings = "Collective Settings"
|
||||
, insights = "Insights"
|
||||
, sources = "Sources"
|
||||
, settings = "Settings"
|
||||
, users = "Users"
|
||||
, shares = "Shares"
|
||||
, user = "User"
|
||||
, collective = "Collective"
|
||||
, size = "Size"
|
||||
@ -64,12 +69,14 @@ de =
|
||||
, userManage = Messages.Comp.UserManage.de
|
||||
, collectiveSettingsForm = Messages.Comp.CollectiveSettingsForm.de
|
||||
, sourceManage = Messages.Comp.SourceManage.de
|
||||
, shareManage = Messages.Comp.ShareManage.de
|
||||
, httpError = Messages.Comp.HttpError.de
|
||||
, collectiveSettings = "Kollektiveinstellungen"
|
||||
, insights = "Statistiken"
|
||||
, sources = "Quellen"
|
||||
, settings = "Einstellungen"
|
||||
, users = "Benutzer"
|
||||
, shares = "Freigaben"
|
||||
, user = "Benutzer"
|
||||
, collective = "Kollektiv"
|
||||
, size = "Größe"
|
||||
|
@ -17,6 +17,7 @@ import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.CollectiveSettings exposing (CollectiveSettings)
|
||||
import Api.Model.ItemInsights exposing (ItemInsights)
|
||||
import Comp.CollectiveSettingsForm
|
||||
import Comp.ShareManage
|
||||
import Comp.SourceManage
|
||||
import Comp.UserManage
|
||||
import Data.Flags exposing (Flags)
|
||||
@ -28,6 +29,7 @@ type alias Model =
|
||||
, sourceModel : Comp.SourceManage.Model
|
||||
, userModel : Comp.UserManage.Model
|
||||
, settingsModel : Comp.CollectiveSettingsForm.Model
|
||||
, shareModel : Comp.ShareManage.Model
|
||||
, insights : ItemInsights
|
||||
, formState : FormState
|
||||
}
|
||||
@ -48,10 +50,14 @@ init flags =
|
||||
|
||||
( cm, cc ) =
|
||||
Comp.CollectiveSettingsForm.init flags Api.Model.CollectiveSettings.empty
|
||||
|
||||
( shm, shc ) =
|
||||
Comp.ShareManage.init
|
||||
in
|
||||
( { currentTab = Just InsightsTab
|
||||
, sourceModel = sm
|
||||
, userModel = Comp.UserManage.emptyModel
|
||||
, shareModel = shm
|
||||
, settingsModel = cm
|
||||
, insights = Api.Model.ItemInsights.empty
|
||||
, formState = InitialState
|
||||
@ -59,6 +65,7 @@ init flags =
|
||||
, Cmd.batch
|
||||
[ Cmd.map SourceMsg sc
|
||||
, Cmd.map SettingsFormMsg cc
|
||||
, Cmd.map ShareMsg shc
|
||||
]
|
||||
)
|
||||
|
||||
@ -68,6 +75,7 @@ type Tab
|
||||
| UserTab
|
||||
| InsightsTab
|
||||
| SettingsTab
|
||||
| ShareTab
|
||||
|
||||
|
||||
type Msg
|
||||
@ -79,3 +87,4 @@ type Msg
|
||||
| GetInsightsResp (Result Http.Error ItemInsights)
|
||||
| CollectiveSettingsResp (Result Http.Error CollectiveSettings)
|
||||
| SubmitResp (Result Http.Error BasicResult)
|
||||
| ShareMsg Comp.ShareManage.Msg
|
||||
|
@ -9,6 +9,7 @@ module Page.CollectiveSettings.Update exposing (update)
|
||||
|
||||
import Api
|
||||
import Comp.CollectiveSettingsForm
|
||||
import Comp.ShareManage
|
||||
import Comp.SourceManage
|
||||
import Comp.UserManage
|
||||
import Data.Flags exposing (Flags)
|
||||
@ -36,6 +37,9 @@ update flags msg model =
|
||||
SettingsTab ->
|
||||
update flags Init m
|
||||
|
||||
ShareTab ->
|
||||
update flags (ShareMsg Comp.ShareManage.loadShares) m
|
||||
|
||||
SourceMsg m ->
|
||||
let
|
||||
( m2, c2 ) =
|
||||
@ -43,6 +47,13 @@ update flags msg model =
|
||||
in
|
||||
( { model | sourceModel = m2 }, Cmd.map SourceMsg c2 )
|
||||
|
||||
ShareMsg lm ->
|
||||
let
|
||||
( sm, sc ) =
|
||||
Comp.ShareManage.update flags lm model.shareModel
|
||||
in
|
||||
( { model | shareModel = sm }, Cmd.map ShareMsg sc )
|
||||
|
||||
UserMsg m ->
|
||||
let
|
||||
( m2, c2 ) =
|
||||
|
@ -10,6 +10,7 @@ module Page.CollectiveSettings.View2 exposing (viewContent, viewSidebar)
|
||||
import Api.Model.TagCount exposing (TagCount)
|
||||
import Comp.Basic as B
|
||||
import Comp.CollectiveSettingsForm
|
||||
import Comp.ShareManage
|
||||
import Comp.SourceManage
|
||||
import Comp.UserManage
|
||||
import Data.Flags exposing (Flags)
|
||||
@ -60,6 +61,17 @@ viewSidebar texts visible _ _ model =
|
||||
[ class "ml-3" ]
|
||||
[ text texts.sources ]
|
||||
]
|
||||
, a
|
||||
[ href "#"
|
||||
, onClick (SetTab ShareTab)
|
||||
, class S.sidebarLink
|
||||
, menuEntryActive model ShareTab
|
||||
]
|
||||
[ Icons.shareIcon ""
|
||||
, span
|
||||
[ class "ml-3" ]
|
||||
[ text texts.shares ]
|
||||
]
|
||||
, a
|
||||
[ href "#"
|
||||
, onClick (SetTab SettingsTab)
|
||||
@ -105,6 +117,9 @@ viewContent texts flags settings model =
|
||||
Just SourceTab ->
|
||||
viewSources texts flags settings model
|
||||
|
||||
Just ShareTab ->
|
||||
viewShares texts flags model
|
||||
|
||||
Nothing ->
|
||||
[]
|
||||
)
|
||||
@ -230,6 +245,21 @@ viewSources texts flags settings model =
|
||||
]
|
||||
|
||||
|
||||
viewShares : Texts -> Flags -> Model -> List (Html Msg)
|
||||
viewShares texts flags model =
|
||||
[ h1
|
||||
[ class S.header1
|
||||
, class "inline-flex items-center"
|
||||
]
|
||||
[ Icons.shareIcon ""
|
||||
, div [ class "ml-3" ]
|
||||
[ text texts.shares
|
||||
]
|
||||
]
|
||||
, Html.map ShareMsg (Comp.ShareManage.view texts.shareManage flags model.shareModel)
|
||||
]
|
||||
|
||||
|
||||
viewUsers : Texts -> UiSettings -> Model -> List (Html Msg)
|
||||
viewUsers texts settings model =
|
||||
[ h1
|
||||
|
Reference in New Issue
Block a user