mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-28 11:08:27 +00:00
Show item detail for a shared item
This commit is contained in:
@ -5,7 +5,7 @@
|
||||
-}
|
||||
|
||||
|
||||
module Page.Share.Data exposing (Mode(..), Model, Msg(..), PageError(..), init)
|
||||
module Page.Share.Data exposing (Mode(..), Model, Msg(..), PageError(..), init, initCmd)
|
||||
|
||||
import Api
|
||||
import Api.Model.ItemLightList exposing (ItemLightList)
|
||||
@ -41,6 +41,7 @@ type alias Model =
|
||||
, powerSearchInput : Comp.PowerSearchInput.Model
|
||||
, searchInProgress : Bool
|
||||
, itemListModel : Comp.ItemCardList.Model
|
||||
, initialized : Bool
|
||||
}
|
||||
|
||||
|
||||
@ -54,17 +55,27 @@ emptyModel flags =
|
||||
, powerSearchInput = Comp.PowerSearchInput.init
|
||||
, searchInProgress = False
|
||||
, itemListModel = Comp.ItemCardList.init
|
||||
, initialized = False
|
||||
}
|
||||
|
||||
|
||||
init : Maybe String -> Flags -> ( Model, Cmd Msg )
|
||||
init shareId flags =
|
||||
let
|
||||
em =
|
||||
emptyModel flags
|
||||
in
|
||||
case shareId of
|
||||
Just id ->
|
||||
( emptyModel flags, Api.verifyShare flags (ShareSecret id Nothing) VerifyResp )
|
||||
( { em | initialized = True }, Api.verifyShare flags (ShareSecret id Nothing) VerifyResp )
|
||||
|
||||
Nothing ->
|
||||
( emptyModel flags, Cmd.none )
|
||||
( em, Cmd.none )
|
||||
|
||||
|
||||
initCmd : String -> Flags -> Cmd Msg
|
||||
initCmd shareId flags =
|
||||
Api.verifyShare flags (ShareSecret shareId Nothing) VerifyResp
|
||||
|
||||
|
||||
type Msg
|
||||
|
@ -42,13 +42,18 @@ viewContent texts flags versionInfo uiSettings shareId model =
|
||||
ModeInitial ->
|
||||
div
|
||||
[ id "content"
|
||||
, class "h-full w-full flex flex-col text-5xl"
|
||||
, class "h-full w-full flex flex-col"
|
||||
, class S.content
|
||||
]
|
||||
[ B.loadingDimmer
|
||||
{ active = model.pageError == PageErrorNone
|
||||
, label = ""
|
||||
}
|
||||
[ div [ class " text-5xl" ]
|
||||
[ B.loadingDimmer
|
||||
{ active = model.pageError == PageErrorNone
|
||||
, label = ""
|
||||
}
|
||||
]
|
||||
, div [ class "my-4 text-lg" ]
|
||||
[ errorMessage texts model
|
||||
]
|
||||
]
|
||||
|
||||
ModePassword ->
|
||||
@ -76,10 +81,28 @@ mainContent texts flags settings shareId model =
|
||||
[ text <| Maybe.withDefault "" model.verifyResult.name
|
||||
]
|
||||
, Menubar.view texts model
|
||||
, errorMessage texts model
|
||||
, Results.view texts settings flags shareId model
|
||||
]
|
||||
|
||||
|
||||
errorMessage : Texts -> Model -> Html Msg
|
||||
errorMessage texts model =
|
||||
case model.pageError of
|
||||
PageErrorNone ->
|
||||
span [ class "hidden" ] []
|
||||
|
||||
PageErrorAuthFail ->
|
||||
div [ class S.errorMessage ]
|
||||
[ text texts.authFailed
|
||||
]
|
||||
|
||||
PageErrorHttp err ->
|
||||
div [ class S.errorMessage ]
|
||||
[ text (texts.httpError err)
|
||||
]
|
||||
|
||||
|
||||
passwordContent : Texts -> Flags -> VersionInfo -> Model -> Html Msg
|
||||
passwordContent texts flags versionInfo model =
|
||||
div
|
||||
|
@ -5,6 +5,7 @@ import Api.Model.ItemDetail exposing (ItemDetail)
|
||||
import Api.Model.ShareSecret exposing (ShareSecret)
|
||||
import Api.Model.ShareVerifyResult exposing (ShareVerifyResult)
|
||||
import Comp.SharePasswordForm
|
||||
import Comp.UrlCopy
|
||||
import Data.Flags exposing (Flags)
|
||||
import Http
|
||||
|
||||
@ -27,6 +28,8 @@ type alias Model =
|
||||
, passwordModel : Comp.SharePasswordForm.Model
|
||||
, viewMode : ViewMode
|
||||
, pageError : PageError
|
||||
, attachMenuOpen : Bool
|
||||
, visibleAttach : Int
|
||||
}
|
||||
|
||||
|
||||
@ -34,6 +37,9 @@ type Msg
|
||||
= VerifyResp (Result Http.Error ShareVerifyResult)
|
||||
| GetItemResp (Result Http.Error ItemDetail)
|
||||
| PasswordMsg Comp.SharePasswordForm.Msg
|
||||
| SelectActiveAttachment Int
|
||||
| ToggleSelectAttach
|
||||
| UrlCopyMsg Comp.UrlCopy.Msg
|
||||
|
||||
|
||||
emptyModel : ViewMode -> Model
|
||||
@ -43,14 +49,18 @@ emptyModel vm =
|
||||
, passwordModel = Comp.SharePasswordForm.init
|
||||
, viewMode = vm
|
||||
, pageError = PageErrorNone
|
||||
, attachMenuOpen = False
|
||||
, visibleAttach = 0
|
||||
}
|
||||
|
||||
|
||||
init : Maybe ( String, String ) -> Flags -> ( Model, Cmd Msg )
|
||||
init mids flags =
|
||||
case mids of
|
||||
Just ( shareId, _ ) ->
|
||||
( emptyModel ViewLoading, Api.verifyShare flags (ShareSecret shareId Nothing) VerifyResp )
|
||||
Just ( shareId, itemId ) ->
|
||||
( emptyModel ViewLoading
|
||||
, Api.verifyShare flags (ShareSecret shareId Nothing) VerifyResp
|
||||
)
|
||||
|
||||
Nothing ->
|
||||
( emptyModel ViewLoading, Cmd.none )
|
||||
|
@ -2,7 +2,9 @@ module Page.ShareDetail.Update exposing (update)
|
||||
|
||||
import Api
|
||||
import Comp.SharePasswordForm
|
||||
import Comp.UrlCopy
|
||||
import Data.Flags exposing (Flags)
|
||||
import Page exposing (Page(..))
|
||||
import Page.ShareDetail.Data exposing (..)
|
||||
|
||||
|
||||
@ -36,12 +38,16 @@ update shareId itemId flags msg model =
|
||||
( { model | pageError = PageErrorHttp err }, Cmd.none )
|
||||
|
||||
GetItemResp (Ok item) ->
|
||||
let
|
||||
url =
|
||||
Page.pageToString (ShareDetailPage shareId itemId)
|
||||
in
|
||||
( { model
|
||||
| item = item
|
||||
, viewMode = ViewNormal
|
||||
, pageError = PageErrorNone
|
||||
}
|
||||
, Cmd.none
|
||||
, Comp.UrlCopy.initCopy url
|
||||
)
|
||||
|
||||
GetItemResp (Err err) ->
|
||||
@ -62,3 +68,21 @@ update shareId itemId flags msg model =
|
||||
|
||||
Nothing ->
|
||||
( { model | passwordModel = m }, Cmd.map PasswordMsg c )
|
||||
|
||||
SelectActiveAttachment pos ->
|
||||
( { model
|
||||
| visibleAttach = pos
|
||||
, attachMenuOpen = False
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
ToggleSelectAttach ->
|
||||
( { model | attachMenuOpen = not model.attachMenuOpen }, Cmd.none )
|
||||
|
||||
UrlCopyMsg lm ->
|
||||
let
|
||||
cmd =
|
||||
Comp.UrlCopy.update lm
|
||||
in
|
||||
( model, cmd )
|
||||
|
@ -1,30 +1,41 @@
|
||||
module Page.ShareDetail.View exposing (viewContent, viewSidebar)
|
||||
|
||||
import Api
|
||||
import Api.Model.Attachment exposing (Attachment)
|
||||
import Api.Model.VersionInfo exposing (VersionInfo)
|
||||
import Comp.Basic as B
|
||||
import Comp.SharePasswordForm
|
||||
import Comp.UrlCopy
|
||||
import Data.Fields
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.Icons as Icons
|
||||
import Data.ItemTemplate as IT exposing (ItemTemplate)
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Messages.Page.ShareDetail exposing (Texts)
|
||||
import Page exposing (Page(..))
|
||||
import Page.ShareDetail.Data exposing (..)
|
||||
import Styles as S
|
||||
import Util.CustomField
|
||||
import Util.Item
|
||||
import Util.List
|
||||
import Util.Size
|
||||
import Util.String
|
||||
|
||||
|
||||
viewSidebar : Texts -> Bool -> Flags -> UiSettings -> Model -> Html Msg
|
||||
viewSidebar texts visible flags settings model =
|
||||
viewSidebar : Texts -> Bool -> Flags -> UiSettings -> String -> String -> Model -> Html Msg
|
||||
viewSidebar texts visible flags settings shareId itemId model =
|
||||
div
|
||||
[ id "sidebar"
|
||||
, class "hidden"
|
||||
, classList [ ( "hidden", not visible ) ]
|
||||
, class S.sidebar
|
||||
]
|
||||
[ div [ class "pt-2" ]
|
||||
[ itemData texts flags model shareId itemId
|
||||
]
|
||||
]
|
||||
[]
|
||||
|
||||
|
||||
viewContent : Texts -> Flags -> UiSettings -> VersionInfo -> String -> String -> Model -> Html Msg
|
||||
@ -36,10 +47,15 @@ viewContent texts flags uiSettings versionInfo shareId itemId model =
|
||||
, class "h-full w-full flex flex-col text-5xl"
|
||||
, class S.content
|
||||
]
|
||||
[ B.loadingDimmer
|
||||
{ active = model.pageError == PageErrorNone
|
||||
, label = ""
|
||||
}
|
||||
[ div [ class "text-5xl" ]
|
||||
[ B.loadingDimmer
|
||||
{ active = model.pageError == PageErrorNone
|
||||
, label = ""
|
||||
}
|
||||
]
|
||||
, div [ class "my-4 text-lg" ]
|
||||
[ errorMessage texts model
|
||||
]
|
||||
]
|
||||
|
||||
ViewPassword ->
|
||||
@ -60,18 +76,18 @@ mainContent texts flags settings shareId model =
|
||||
, class S.content
|
||||
]
|
||||
[ itemHead texts shareId model
|
||||
, div [ class "flex flex-col sm:flex-row sm:space-x-4 relative h-full" ]
|
||||
[ itemData texts model
|
||||
, itemPreview texts flags settings model
|
||||
, errorMessage texts model
|
||||
, div [ class "relative h-full" ]
|
||||
[ itemPreview texts flags settings model
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
itemData : Texts -> Model -> Html Msg
|
||||
itemData texts model =
|
||||
itemData : Texts -> Flags -> Model -> String -> String -> Html Msg
|
||||
itemData texts flags model shareId itemId =
|
||||
let
|
||||
boxStyle =
|
||||
"mb-4 sm:mb-6 max-w-sm"
|
||||
"mb-4 sm:mb-6"
|
||||
|
||||
headerStyle =
|
||||
"py-2 bg-blue-50 hover:bg-blue-100 dark:bg-bluegray-700 dark:hover:bg-opacity-100 dark:hover:bg-bluegray-600 text-lg font-medium rounded-lg"
|
||||
@ -92,11 +108,11 @@ itemData texts model =
|
||||
]
|
||||
Nothing
|
||||
in
|
||||
div [ class "flex flex-col pr-2 sm:w-1/3" ]
|
||||
div [ class "flex flex-col" ]
|
||||
[ div [ class boxStyle ]
|
||||
[ div [ class headerStyle ]
|
||||
[ Icons.dateIcon2 "mr-2 ml-2"
|
||||
, text "Date"
|
||||
, text (texts.field Data.Fields.Date)
|
||||
]
|
||||
, div [ class "text-lg ml-2" ]
|
||||
[ Util.Item.toItemLight model.item
|
||||
@ -104,10 +120,24 @@ itemData texts model =
|
||||
|> text
|
||||
]
|
||||
]
|
||||
, div
|
||||
[ class boxStyle
|
||||
, classList [ ( "hidden", model.item.dueDate == Nothing ) ]
|
||||
]
|
||||
[ div [ class headerStyle ]
|
||||
[ Icons.dueDateIcon2 "mr-2 ml-2"
|
||||
, text (texts.field Data.Fields.DueDate)
|
||||
]
|
||||
, div [ class "text-lg ml-2" ]
|
||||
[ Util.Item.toItemLight model.item
|
||||
|> IT.render IT.dueDateLong (templateCtx texts)
|
||||
|> text
|
||||
]
|
||||
]
|
||||
, div [ class boxStyle ]
|
||||
[ div [ class headerStyle ]
|
||||
[ Icons.tagsIcon2 "mr-2 ml-2"
|
||||
, text "Tags & Fields"
|
||||
, text texts.tagsAndFields
|
||||
]
|
||||
, div [ class "flex flex-row items-center flex-wrap font-medium my-1" ]
|
||||
(List.map showTag model.item.tags ++ List.map showField model.item.customfields)
|
||||
@ -115,7 +145,7 @@ itemData texts model =
|
||||
, div [ class boxStyle ]
|
||||
[ div [ class headerStyle ]
|
||||
[ Icons.correspondentIcon2 "mr-2 ml-2"
|
||||
, text "Correspondent"
|
||||
, text texts.basics.correspondent
|
||||
]
|
||||
, div [ class "text-lg ml-2" ]
|
||||
[ Util.Item.toItemLight model.item
|
||||
@ -126,7 +156,7 @@ itemData texts model =
|
||||
, div [ class boxStyle ]
|
||||
[ div [ class headerStyle ]
|
||||
[ Icons.concernedIcon2 "mr-2 ml-2"
|
||||
, text "Concerning"
|
||||
, text texts.basics.concerning
|
||||
]
|
||||
, div [ class "text-lg ml-2" ]
|
||||
[ Util.Item.toItemLight model.item
|
||||
@ -134,40 +164,110 @@ itemData texts model =
|
||||
|> text
|
||||
]
|
||||
]
|
||||
, div [ class boxStyle ]
|
||||
[ div [ class headerStyle ]
|
||||
[ i [ class "fa fa-copy mr-2 ml-2" ] []
|
||||
, text "Copy URL"
|
||||
]
|
||||
, div [ class "flex flex-col items-center py-2" ]
|
||||
[ Html.map UrlCopyMsg
|
||||
(Comp.UrlCopy.view
|
||||
(flags.config.baseUrl
|
||||
++ Page.pageToString
|
||||
(ShareDetailPage shareId itemId)
|
||||
)
|
||||
)
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
itemPreview : Texts -> Flags -> UiSettings -> Model -> Html Msg
|
||||
itemPreview texts flags settings model =
|
||||
let
|
||||
id =
|
||||
List.head model.item.attachments
|
||||
|> Maybe.map .id
|
||||
|> Maybe.withDefault ""
|
||||
attach =
|
||||
Util.List.get model.item.attachments model.visibleAttach
|
||||
|> Maybe.withDefault Api.Model.Attachment.empty
|
||||
|
||||
attachName =
|
||||
Maybe.withDefault (texts.noName ++ ".pdf") attach.name
|
||||
in
|
||||
div
|
||||
[ class "flex flex-grow"
|
||||
, style "min-height" "500px"
|
||||
[ class "flex flex-grow flex-col h-full border-t dark:border-bluegray-600"
|
||||
]
|
||||
[ embed
|
||||
[ src (Data.UiSettings.pdfUrl settings flags (Api.shareFileURL id))
|
||||
, class " h-full w-full mx-0 py-0"
|
||||
[ div [ class "flex flex-col sm:flex-row items-center py-1 px-1 border-l border-r dark:border-bluegray-600" ]
|
||||
[ div [ class "text-base font-bold flex-grow w-full text-center sm:text-left break-all" ]
|
||||
[ text attachName
|
||||
, text " ("
|
||||
, text (Util.Size.bytesReadable Util.Size.B (toFloat attach.size))
|
||||
, text ")"
|
||||
]
|
||||
, div [ class "flex flex-row space-x-2" ]
|
||||
[ B.secondaryBasicButton
|
||||
{ label = ""
|
||||
, icon = "fa fa-eye"
|
||||
, disabled = False
|
||||
, handler = href (Api.shareFileURL attach.id)
|
||||
, attrs =
|
||||
[ target "_new"
|
||||
]
|
||||
}
|
||||
, B.secondaryBasicButton
|
||||
{ label = ""
|
||||
, icon = "fa fa-download"
|
||||
, disabled = False
|
||||
, handler = href (Api.shareFileURL attach.id)
|
||||
, attrs =
|
||||
[ download attachName
|
||||
]
|
||||
}
|
||||
, B.secondaryBasicButton
|
||||
{ label = ""
|
||||
, icon = "fa fa-ellipsis-v"
|
||||
, disabled = False
|
||||
, handler = onClick ToggleSelectAttach
|
||||
, attrs =
|
||||
[ href "#"
|
||||
, classList [ ( "hidden", List.length model.item.attachments <= 1 ) ]
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
, attachmentSelect texts model
|
||||
, div
|
||||
[ class "flex w-full h-full mb-4 border-b border-l border-r dark:border-bluegray-600"
|
||||
, style "min-height" "500px"
|
||||
]
|
||||
[ embed
|
||||
[ src (Data.UiSettings.pdfUrl settings flags (Api.shareFileURL attach.id))
|
||||
, class " h-full w-full mx-0 py-0"
|
||||
]
|
||||
[]
|
||||
]
|
||||
[]
|
||||
]
|
||||
|
||||
|
||||
itemHead : Texts -> String -> Model -> Html Msg
|
||||
itemHead texts shareId model =
|
||||
div [ class "flex flex-col sm:flex-row" ]
|
||||
div [ class "flex flex-col sm:flex-row mt-1" ]
|
||||
[ div [ class "flex flex-grow items-center" ]
|
||||
[ h1 [ class S.header1 ]
|
||||
[ h1
|
||||
[ class S.header1
|
||||
, class "items-center flex flex-row"
|
||||
]
|
||||
[ text model.item.name
|
||||
, span
|
||||
[ classList [ ( "hidden", model.item.state /= "created" ) ]
|
||||
, class S.blueBasicLabel
|
||||
, class "inline ml-4 text-sm"
|
||||
]
|
||||
[ text texts.unconfirmed
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "flex flex-row items-center justify-end mb-2 sm:mb-0" ]
|
||||
[ B.secondaryBasicButton
|
||||
{ label = "Close"
|
||||
{ label = texts.basics.back
|
||||
, icon = "fa fa-times"
|
||||
, disabled = False
|
||||
, handler = Page.href (SharePage shareId)
|
||||
@ -189,6 +289,83 @@ passwordContent texts flags versionInfo model =
|
||||
]
|
||||
|
||||
|
||||
attachmentSelect : Texts -> Model -> Html Msg
|
||||
attachmentSelect texts model =
|
||||
div
|
||||
[ class "flex flex-row border-l border-t border-r px-2 py-2 dark:border-bluegray-600 "
|
||||
, class "overflow-x-auto overflow-y-none"
|
||||
, classList
|
||||
[ ( "hidden", not model.attachMenuOpen )
|
||||
]
|
||||
]
|
||||
(List.indexedMap (menuItem texts model) model.item.attachments)
|
||||
|
||||
|
||||
menuItem : Texts -> Model -> Int -> Attachment -> Html Msg
|
||||
menuItem texts model pos attach =
|
||||
let
|
||||
iconClass =
|
||||
"fa fa-circle ml-1"
|
||||
|
||||
visible =
|
||||
model.visibleAttach == pos
|
||||
in
|
||||
a
|
||||
[ classList <|
|
||||
[ ( "border-blue-500 dark:border-lightblue-500", pos == 0 )
|
||||
, ( "dark:border-bluegray-600", pos /= 0 )
|
||||
]
|
||||
, class "flex flex-col relative border rounded px-1 py-1 mr-2"
|
||||
, class " hover:shadow dark:hover:border-bluegray-500"
|
||||
, href "#"
|
||||
, onClick (SelectActiveAttachment pos)
|
||||
]
|
||||
[ div
|
||||
[ classList
|
||||
[ ( "hidden", not visible )
|
||||
]
|
||||
, class "absolute right-1 top-1 text-blue-400 dark:text-lightblue-400 text-xl"
|
||||
]
|
||||
[ i [ class iconClass ] []
|
||||
]
|
||||
, div [ class "flex-grow" ]
|
||||
[ img
|
||||
[ src (Api.shareAttachmentPreviewURL attach.id)
|
||||
, class "block w-20 mx-auto"
|
||||
]
|
||||
[]
|
||||
]
|
||||
, div [ class "mt-1 text-sm break-all w-28 text-center" ]
|
||||
[ Maybe.map (Util.String.ellipsis 36) attach.name
|
||||
|> Maybe.withDefault texts.noName
|
||||
|> text
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
errorMessage : Texts -> Model -> Html Msg
|
||||
errorMessage texts model =
|
||||
case model.pageError of
|
||||
PageErrorNone ->
|
||||
span [ class "hidden" ] []
|
||||
|
||||
PageErrorAuthFail ->
|
||||
div
|
||||
[ class S.errorMessage
|
||||
, class "my-4"
|
||||
]
|
||||
[ text texts.authFailed
|
||||
]
|
||||
|
||||
PageErrorHttp err ->
|
||||
div
|
||||
[ class S.errorMessage
|
||||
, class "my-4"
|
||||
]
|
||||
[ text (texts.httpError err)
|
||||
]
|
||||
|
||||
|
||||
templateCtx : Texts -> IT.TemplateContext
|
||||
templateCtx texts =
|
||||
{ dateFormatLong = texts.formatDateLong
|
||||
|
Reference in New Issue
Block a user