mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-23 10:58:26 +00:00
Create shares from search and select view
This commit is contained in:
292
modules/webapp/src/main/elm/Comp/PublishItems.elm
Normal file
292
modules/webapp/src/main/elm/Comp/PublishItems.elm
Normal file
@ -0,0 +1,292 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.PublishItems exposing
|
||||
( Model
|
||||
, Msg
|
||||
, Outcome(..)
|
||||
, init
|
||||
, initQuery
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api
|
||||
import Api.Model.IdResult exposing (IdResult)
|
||||
import Api.Model.ShareDetail exposing (ShareDetail)
|
||||
import Comp.Basic as B
|
||||
import Comp.MenuBar as MB
|
||||
import Comp.ShareForm
|
||||
import Comp.ShareView
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.Icons as Icons
|
||||
import Data.ItemQuery exposing (ItemQuery)
|
||||
import Data.SearchMode exposing (SearchMode)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Http
|
||||
import Messages.Comp.PublishItems exposing (Texts)
|
||||
import Ports
|
||||
import Styles as S
|
||||
|
||||
|
||||
|
||||
--- Model
|
||||
|
||||
|
||||
type ViewMode
|
||||
= ViewModeEdit
|
||||
| ViewModeInfo ShareDetail
|
||||
|
||||
|
||||
type FormError
|
||||
= FormErrorNone
|
||||
| FormErrorHttp Http.Error
|
||||
| FormErrorInvalid
|
||||
| FormErrorSubmit String
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ formModel : Comp.ShareForm.Model
|
||||
, viewMode : ViewMode
|
||||
, formError : FormError
|
||||
, loading : Bool
|
||||
}
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
let
|
||||
( fm, fc ) =
|
||||
Comp.ShareForm.init
|
||||
in
|
||||
( { formModel = fm
|
||||
, viewMode = ViewModeEdit
|
||||
, formError = FormErrorNone
|
||||
, loading = False
|
||||
}
|
||||
, Cmd.map FormMsg fc
|
||||
)
|
||||
|
||||
|
||||
initQuery : ItemQuery -> ( Model, Cmd Msg )
|
||||
initQuery query =
|
||||
let
|
||||
( fm, fc ) =
|
||||
Comp.ShareForm.initQuery (Data.ItemQuery.render query)
|
||||
in
|
||||
( { formModel = fm
|
||||
, viewMode = ViewModeEdit
|
||||
, formError = FormErrorNone
|
||||
, loading = False
|
||||
}
|
||||
, Cmd.map FormMsg fc
|
||||
)
|
||||
|
||||
|
||||
|
||||
--- Update
|
||||
|
||||
|
||||
type Msg
|
||||
= FormMsg Comp.ShareForm.Msg
|
||||
| CancelPublish
|
||||
| SubmitPublish
|
||||
| PublishResp (Result Http.Error IdResult)
|
||||
| GetShareResp (Result Http.Error ShareDetail)
|
||||
|
||||
|
||||
type Outcome
|
||||
= OutcomeDone
|
||||
| OutcomeInProgress
|
||||
|
||||
|
||||
type alias UpdateResult =
|
||||
{ model : Model
|
||||
, cmd : Cmd Msg
|
||||
, outcome : Outcome
|
||||
}
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> UpdateResult
|
||||
update flags msg model =
|
||||
case msg of
|
||||
CancelPublish ->
|
||||
{ model = model
|
||||
, cmd = Cmd.none
|
||||
, outcome = OutcomeDone
|
||||
}
|
||||
|
||||
FormMsg lm ->
|
||||
let
|
||||
( fm, fc ) =
|
||||
Comp.ShareForm.update flags lm model.formModel
|
||||
in
|
||||
{ model = { model | formModel = fm }
|
||||
, cmd = Cmd.map FormMsg fc
|
||||
, outcome = OutcomeInProgress
|
||||
}
|
||||
|
||||
SubmitPublish ->
|
||||
case Comp.ShareForm.getShare model.formModel of
|
||||
Just ( _, data ) ->
|
||||
{ model = { model | loading = True }
|
||||
, cmd = Api.addShare flags data PublishResp
|
||||
, outcome = OutcomeInProgress
|
||||
}
|
||||
|
||||
Nothing ->
|
||||
{ model = { model | formError = FormErrorInvalid }
|
||||
, cmd = Cmd.none
|
||||
, outcome = OutcomeInProgress
|
||||
}
|
||||
|
||||
PublishResp (Ok res) ->
|
||||
if res.success then
|
||||
{ model = model
|
||||
, cmd = Api.getShare flags res.id GetShareResp
|
||||
, outcome = OutcomeInProgress
|
||||
}
|
||||
|
||||
else
|
||||
{ model = { model | formError = FormErrorSubmit res.message, loading = False }
|
||||
, cmd = Cmd.none
|
||||
, outcome = OutcomeInProgress
|
||||
}
|
||||
|
||||
PublishResp (Err err) ->
|
||||
{ model = { model | formError = FormErrorHttp err, loading = False }
|
||||
, cmd = Cmd.none
|
||||
, outcome = OutcomeInProgress
|
||||
}
|
||||
|
||||
GetShareResp (Ok share) ->
|
||||
{ model =
|
||||
{ model
|
||||
| formError = FormErrorNone
|
||||
, loading = False
|
||||
, viewMode = ViewModeInfo share
|
||||
}
|
||||
, cmd = Ports.initClipboard (Comp.ShareView.clipboardData share)
|
||||
, outcome = OutcomeInProgress
|
||||
}
|
||||
|
||||
GetShareResp (Err err) ->
|
||||
{ model = { model | formError = FormErrorHttp err, loading = False }
|
||||
, cmd = Cmd.none
|
||||
, outcome = OutcomeInProgress
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- View
|
||||
|
||||
|
||||
view : Texts -> Flags -> Model -> Html Msg
|
||||
view texts flags model =
|
||||
div []
|
||||
[ B.loadingDimmer
|
||||
{ active = model.loading
|
||||
, label = ""
|
||||
}
|
||||
, case model.viewMode of
|
||||
ViewModeEdit ->
|
||||
viewForm texts model
|
||||
|
||||
ViewModeInfo share ->
|
||||
viewInfo texts flags model share
|
||||
]
|
||||
|
||||
|
||||
viewInfo : Texts -> Flags -> Model -> ShareDetail -> Html Msg
|
||||
viewInfo texts flags model share =
|
||||
let
|
||||
cfg =
|
||||
{ mainClasses = ""
|
||||
, showAccessData = False
|
||||
}
|
||||
in
|
||||
div [ class "px-2 mb-4" ]
|
||||
[ h1 [ class S.header1 ]
|
||||
[ text texts.title
|
||||
]
|
||||
, div
|
||||
[ class S.infoMessage
|
||||
]
|
||||
[ text texts.infoText
|
||||
]
|
||||
, MB.view <|
|
||||
{ start =
|
||||
[ MB.SecondaryButton
|
||||
{ tagger = CancelPublish
|
||||
, title = texts.cancelPublishTitle
|
||||
, icon = Just "fa fa-arrow-left"
|
||||
, label = texts.doneLabel
|
||||
}
|
||||
]
|
||||
, end = []
|
||||
, rootClasses = "my-4"
|
||||
}
|
||||
, div []
|
||||
[ Comp.ShareView.view cfg texts.shareView flags share
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
viewForm : Texts -> Model -> Html Msg
|
||||
viewForm texts model =
|
||||
div [ class "px-2 mb-4" ]
|
||||
[ h1 [ class S.header1 ]
|
||||
[ text texts.title
|
||||
]
|
||||
, div
|
||||
[ class S.infoMessage
|
||||
]
|
||||
[ text texts.infoText
|
||||
]
|
||||
, MB.view <|
|
||||
{ start =
|
||||
[ MB.PrimaryButton
|
||||
{ tagger = SubmitPublish
|
||||
, title = texts.submitPublishTitle
|
||||
, icon = Just Icons.share
|
||||
, label = texts.submitPublish
|
||||
}
|
||||
, MB.SecondaryButton
|
||||
{ tagger = CancelPublish
|
||||
, title = texts.cancelPublishTitle
|
||||
, icon = Just "fa fa-times"
|
||||
, label = texts.cancelPublish
|
||||
}
|
||||
]
|
||||
, end = []
|
||||
, rootClasses = "my-4"
|
||||
}
|
||||
, div []
|
||||
[ Html.map FormMsg (Comp.ShareForm.view texts.shareForm model.formModel)
|
||||
]
|
||||
, 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
|
||||
]
|
||||
]
|
@ -5,7 +5,7 @@
|
||||
-}
|
||||
|
||||
|
||||
module Comp.ShareForm exposing (Model, Msg, getShare, init, setShare, update, view)
|
||||
module Comp.ShareForm exposing (Model, Msg, getShare, init, initQuery, setShare, update, view)
|
||||
|
||||
import Api.Model.ShareData exposing (ShareData)
|
||||
import Api.Model.ShareDetail exposing (ShareDetail)
|
||||
@ -36,16 +36,16 @@ type alias Model =
|
||||
}
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
initQuery : String -> ( Model, Cmd Msg )
|
||||
initQuery q =
|
||||
let
|
||||
( dp, dpc ) =
|
||||
Comp.DatePicker.init
|
||||
in
|
||||
( { share = Api.Model.ShareDetail.empty
|
||||
, name = Nothing
|
||||
, query = ""
|
||||
, enabled = False
|
||||
, query = q
|
||||
, enabled = True
|
||||
, passwordModel = Comp.PasswordInput.init
|
||||
, password = Nothing
|
||||
, passwordSet = False
|
||||
@ -57,6 +57,11 @@ init =
|
||||
)
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
initQuery ""
|
||||
|
||||
|
||||
isValid : Model -> Bool
|
||||
isValid model =
|
||||
model.query /= "" && model.untilDate /= Nothing
|
||||
@ -206,7 +211,7 @@ view texts model =
|
||||
, class S.textInput
|
||||
, classList
|
||||
[ ( S.inputErrorBorder
|
||||
, not (isValid model)
|
||||
, model.query == ""
|
||||
)
|
||||
]
|
||||
]
|
||||
@ -265,12 +270,16 @@ view texts model =
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "mb-2 max-w-sm" ]
|
||||
, div
|
||||
[ class "mb-2 max-w-sm"
|
||||
]
|
||||
[ label [ class S.inputLabel ]
|
||||
[ text texts.publishUntil
|
||||
, B.inputRequired
|
||||
]
|
||||
, div [ class "relative" ]
|
||||
, div
|
||||
[ class "relative"
|
||||
]
|
||||
[ Html.map UntilDateMsg
|
||||
(Comp.DatePicker.viewTimeDefault
|
||||
model.untilDate
|
||||
@ -278,5 +287,15 @@ view texts model =
|
||||
)
|
||||
, i [ class S.dateInputIcon, class "fa fa-calendar" ] []
|
||||
]
|
||||
, div
|
||||
[ classList
|
||||
[ ( "hidden"
|
||||
, model.untilDate /= Nothing
|
||||
)
|
||||
]
|
||||
, class "mt-1"
|
||||
, class S.errorText
|
||||
]
|
||||
[ text "This field is required." ]
|
||||
]
|
||||
]
|
||||
|
@ -17,12 +17,14 @@ import Comp.ItemDetail.Model exposing (Msg(..))
|
||||
import Comp.MenuBar as MB
|
||||
import Comp.ShareForm
|
||||
import Comp.ShareTable
|
||||
import Comp.ShareView
|
||||
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 Ports
|
||||
import Styles as S
|
||||
|
||||
|
||||
@ -107,7 +109,7 @@ update flags msg model =
|
||||
share =
|
||||
Api.Model.ShareDetail.empty
|
||||
in
|
||||
update flags (FormMsg (Comp.ShareForm.setShare share)) nm
|
||||
update flags (FormMsg (Comp.ShareForm.setShare { share | enabled = True })) nm
|
||||
|
||||
SetViewMode vm ->
|
||||
( { model | viewMode = vm, formError = FormErrorNone }
|
||||
@ -129,13 +131,10 @@ update flags msg model =
|
||||
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
|
||||
setShare share flags model
|
||||
|
||||
RequestDelete ->
|
||||
( { model | deleteConfirm = DeleteConfirmOn }, Cmd.none )
|
||||
@ -190,11 +189,7 @@ update flags msg model =
|
||||
( { 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
|
||||
setShare share flags model
|
||||
|
||||
GetShareResp (Err err) ->
|
||||
( { model | formError = FormErrorHttp err }, Cmd.none )
|
||||
@ -210,17 +205,32 @@ update flags msg model =
|
||||
( { model | formError = FormErrorHttp err, loading = False }, Cmd.none )
|
||||
|
||||
|
||||
setShare : ShareDetail -> Flags -> Model -> ( Model, Cmd Msg )
|
||||
setShare share flags model =
|
||||
let
|
||||
nextModel =
|
||||
{ model | formError = FormErrorNone, viewMode = Form, loading = False }
|
||||
|
||||
initClipboard =
|
||||
Ports.initClipboard (Comp.ShareView.clipboardData share)
|
||||
|
||||
( nm, nc ) =
|
||||
update flags (FormMsg <| Comp.ShareForm.setShare share) nextModel
|
||||
in
|
||||
( nm, Cmd.batch [ initClipboard, nc ] )
|
||||
|
||||
|
||||
|
||||
--- view
|
||||
|
||||
|
||||
view : Texts -> Flags -> Model -> Html Msg
|
||||
view texts _ model =
|
||||
view texts flags model =
|
||||
if model.viewMode == Table then
|
||||
viewTable texts model
|
||||
|
||||
else
|
||||
viewForm texts model
|
||||
viewForm texts flags model
|
||||
|
||||
|
||||
viewTable : Texts -> Model -> Html Msg
|
||||
@ -247,103 +257,119 @@ viewTable texts model =
|
||||
]
|
||||
|
||||
|
||||
viewForm : Texts -> Model -> Html Msg
|
||||
viewForm texts model =
|
||||
viewForm : Texts -> Flags -> Model -> Html Msg
|
||||
viewForm texts flags 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
|
||||
div [ class "relative" ]
|
||||
[ Html.form []
|
||||
[ if newShare then
|
||||
h1 [ class S.header2 ]
|
||||
[ text texts.createNewShare
|
||||
]
|
||||
]
|
||||
, 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
|
||||
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 )
|
||||
else
|
||||
[]
|
||||
, rootClasses = "mb-4"
|
||||
}
|
||||
, div
|
||||
[ classList
|
||||
[ ( "hidden", model.formError == FormErrorNone )
|
||||
]
|
||||
, class "my-2"
|
||||
, class S.errorMessage
|
||||
]
|
||||
, 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" ]
|
||||
}
|
||||
]
|
||||
]
|
||||
)
|
||||
]
|
||||
[ 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" ]
|
||||
}
|
||||
]
|
||||
]
|
||||
)
|
||||
, shareInfo texts flags model.formModel.share
|
||||
]
|
||||
|
||||
|
||||
shareInfo : Texts -> Flags -> ShareDetail -> Html Msg
|
||||
shareInfo texts flags share =
|
||||
div
|
||||
[ class "mt-6"
|
||||
, classList [ ( "hidden", share.id == "" ) ]
|
||||
]
|
||||
[ h2 [ class S.header2 ]
|
||||
[ text texts.shareInformation
|
||||
]
|
||||
, Comp.ShareView.viewDefault texts.shareView flags share
|
||||
]
|
||||
|
@ -54,7 +54,7 @@ view texts shares =
|
||||
[ text texts.basics.name
|
||||
]
|
||||
, th [ class "text-center" ]
|
||||
[ text texts.enabled
|
||||
[ text texts.active
|
||||
]
|
||||
, th [ class "text-center" ]
|
||||
[ text texts.publishUntil
|
||||
@ -79,7 +79,14 @@ renderShareLine texts share =
|
||||
[ text (Maybe.withDefault "-" share.name)
|
||||
]
|
||||
, td [ class "w-px px-2 text-center" ]
|
||||
[ Util.Html.checkbox2 share.enabled
|
||||
[ if not share.enabled then
|
||||
i [ class "fa fa-ban" ] []
|
||||
|
||||
else if share.expired then
|
||||
i [ class "fa fa-bolt text-red-600 dark:text-orange-800" ] []
|
||||
|
||||
else
|
||||
i [ class "fa fa-check" ] []
|
||||
]
|
||||
, td [ class "hidden sm:table-cell text-center" ]
|
||||
[ texts.formatDateTime share.publishUntil |> text
|
||||
|
184
modules/webapp/src/main/elm/Comp/ShareView.elm
Normal file
184
modules/webapp/src/main/elm/Comp/ShareView.elm
Normal file
@ -0,0 +1,184 @@
|
||||
{-
|
||||
Copyright 2020 Eike K. & Contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-}
|
||||
|
||||
|
||||
module Comp.ShareView exposing (ViewSettings, clipboardData, view, viewDefault)
|
||||
|
||||
import Api.Model.ShareDetail exposing (ShareDetail)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Messages.Comp.ShareView exposing (Texts)
|
||||
import QRCode
|
||||
import Styles as S
|
||||
|
||||
|
||||
type alias ViewSettings =
|
||||
{ mainClasses : String
|
||||
, showAccessData : Bool
|
||||
}
|
||||
|
||||
|
||||
view : ViewSettings -> Texts -> Flags -> ShareDetail -> Html msg
|
||||
view cfg texts flags share =
|
||||
if not share.enabled then
|
||||
viewDisabled cfg texts share
|
||||
|
||||
else if share.expired then
|
||||
viewExpired cfg texts share
|
||||
|
||||
else
|
||||
viewActive cfg texts flags share
|
||||
|
||||
|
||||
viewDefault : Texts -> Flags -> ShareDetail -> Html msg
|
||||
viewDefault =
|
||||
view
|
||||
{ mainClasses = ""
|
||||
, showAccessData = True
|
||||
}
|
||||
|
||||
|
||||
clipboardData : ShareDetail -> ( String, String )
|
||||
clipboardData share =
|
||||
( "app-share-" ++ share.id, "#app-share-url-copy-to-clipboard-btn-" ++ share.id )
|
||||
|
||||
|
||||
|
||||
--- Helper
|
||||
|
||||
|
||||
viewActive : ViewSettings -> Texts -> Flags -> ShareDetail -> Html msg
|
||||
viewActive cfg texts flags share =
|
||||
let
|
||||
clipboard =
|
||||
clipboardData share
|
||||
|
||||
appUrl =
|
||||
flags.config.baseUrl ++ "/app/share/" ++ share.id
|
||||
|
||||
styleUrl =
|
||||
"truncate px-2 py-2 border-0 border-t border-b border-r font-mono text-sm my-auto rounded-r border-gray-400 dark:border-bluegray-500"
|
||||
|
||||
infoLine hidden icon label value =
|
||||
div
|
||||
[ class "flex flex-row items-center"
|
||||
, classList [ ( "hidden", hidden ) ]
|
||||
]
|
||||
[ div [ class "flex mr-3" ]
|
||||
[ i [ class icon ] []
|
||||
]
|
||||
, div [ class "flex flex-col" ]
|
||||
[ div [ class "-mb-1" ]
|
||||
[ text value
|
||||
]
|
||||
, div [ class "opacity-50 text-sm" ]
|
||||
[ text label
|
||||
]
|
||||
]
|
||||
]
|
||||
in
|
||||
div
|
||||
[ class cfg.mainClasses
|
||||
, class "flex flex-col sm:flex-row "
|
||||
]
|
||||
[ div [ class "flex" ]
|
||||
[ div
|
||||
[ class S.border
|
||||
, class S.qrCode
|
||||
]
|
||||
[ qrCodeView texts appUrl
|
||||
]
|
||||
]
|
||||
, div
|
||||
[ class "flex flex-col ml-3 pr-2"
|
||||
|
||||
-- hack for the qr code that is 265px
|
||||
, style "max-width" "calc(100% - 265px)"
|
||||
]
|
||||
[ div [ class "font-medium text-2xl" ]
|
||||
[ text <| Maybe.withDefault texts.noName share.name
|
||||
]
|
||||
, div [ class "my-2" ]
|
||||
[ div [ class "flex flex-row" ]
|
||||
[ a
|
||||
[ class S.secondaryBasicButtonPlain
|
||||
, class "rounded-l border text-sm px-4 py-2"
|
||||
, title texts.copyToClipboard
|
||||
, href "#"
|
||||
, Tuple.second clipboard
|
||||
|> String.dropLeft 1
|
||||
|> id
|
||||
, attribute "data-clipboard-target" ("#" ++ Tuple.first clipboard)
|
||||
]
|
||||
[ i [ class "fa fa-copy" ] []
|
||||
]
|
||||
, a
|
||||
[ class S.secondaryBasicButtonPlain
|
||||
, class "px-4 py-2 border-0 border-t border-b border-r text-sm"
|
||||
, href appUrl
|
||||
, target "_blank"
|
||||
, title texts.openInNewTab
|
||||
]
|
||||
[ i [ class "fa fa-external-link-alt" ] []
|
||||
]
|
||||
, div
|
||||
[ id (Tuple.first clipboard)
|
||||
, class styleUrl
|
||||
]
|
||||
[ text appUrl
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "text-lg flex flex-col" ]
|
||||
[ infoLine False "fa fa-calendar" texts.publishUntil (texts.date share.publishUntil)
|
||||
, infoLine False
|
||||
(if share.password then
|
||||
"fa fa-lock"
|
||||
|
||||
else
|
||||
"fa fa-lock-open"
|
||||
)
|
||||
texts.passwordProtected
|
||||
(if share.password then
|
||||
texts.basics.yes
|
||||
|
||||
else
|
||||
texts.basics.no
|
||||
)
|
||||
, infoLine
|
||||
(not cfg.showAccessData)
|
||||
"fa fa-eye"
|
||||
texts.views
|
||||
(String.fromInt share.views)
|
||||
, infoLine
|
||||
(not cfg.showAccessData)
|
||||
"fa fa-calendar-check font-thin"
|
||||
texts.lastAccess
|
||||
(Maybe.map texts.date share.lastAccess |> Maybe.withDefault "-")
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
viewExpired : ViewSettings -> Texts -> ShareDetail -> Html msg
|
||||
viewExpired cfg texts share =
|
||||
div [ class S.warnMessage ]
|
||||
[ text texts.expiredInfo ]
|
||||
|
||||
|
||||
viewDisabled : ViewSettings -> Texts -> ShareDetail -> Html msg
|
||||
viewDisabled cfg texts share =
|
||||
div [ class S.warnMessage ]
|
||||
[ text texts.disabledInfo ]
|
||||
|
||||
|
||||
qrCodeView : Texts -> String -> Html msg
|
||||
qrCodeView texts message =
|
||||
QRCode.encode message
|
||||
|> Result.map QRCode.toSvg
|
||||
|> Result.withDefault
|
||||
(Html.text texts.qrCodeError)
|
Reference in New Issue
Block a user