mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-23 10:58:26 +00:00
Basic management of shares
This commit is contained in:
@ -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
|
||||
]
|
||||
]
|
Reference in New Issue
Block a user