Outline share detail page

This commit is contained in:
eikek 2021-10-06 11:04:18 +02:00
parent 1a10216e3d
commit b6187bb88d
21 changed files with 622 additions and 157 deletions

View File

@ -83,6 +83,7 @@ module Api exposing
, initOtp
, itemBasePreviewURL
, itemDetail
, itemDetailShare
, itemIndexSearch
, itemSearch
, itemSearchStats
@ -2302,6 +2303,15 @@ searchShareStats flags token search receive =
}
itemDetailShare : Flags -> String -> String -> (Result Http.Error ItemDetail -> msg) -> Cmd msg
itemDetailShare flags token itemId receive =
Http2.shareGet
{ url = flags.config.baseUrl ++ "/api/v1/share/item/" ++ itemId
, token = token
, expect = Http.expectJson receive Api.Model.ItemDetail.decoder
}
shareAttachmentPreviewURL : String -> String
shareAttachmentPreviewURL id =
"/api/v1/share/attachment/" ++ id ++ "/preview?withFallback=true"

View File

@ -33,6 +33,7 @@ import Page.NewInvite.Data
import Page.Queue.Data
import Page.Register.Data
import Page.Share.Data
import Page.ShareDetail.Data
import Page.Upload.Data
import Page.UserSettings.Data
import Url exposing (Url)
@ -54,6 +55,7 @@ type alias Model =
, newInviteModel : Page.NewInvite.Data.Model
, itemDetailModel : Page.ItemDetail.Data.Model
, shareModel : Page.Share.Data.Model
, shareDetailModel : Page.ShareDetail.Data.Model
, navMenuOpen : Bool
, userMenuOpen : Bool
, subs : Sub Msg
@ -88,7 +90,10 @@ init key url flags_ settings =
Page.Login.Data.init flags (Page.loginPageReferrer page)
( shm, shc ) =
Page.Share.Data.init (Page.shareId page) flags
Page.Share.Data.init (Page.pageShareId page) flags
( sdm, sdc ) =
Page.ShareDetail.Data.init (Page.pageShareDetail page) flags
homeViewMode =
if settings.searchMenuVisible then
@ -112,6 +117,7 @@ init key url flags_ settings =
, newInviteModel = Page.NewInvite.Data.emptyModel
, itemDetailModel = Page.ItemDetail.Data.emptyModel
, shareModel = shm
, shareDetailModel = sdm
, navMenuOpen = False
, userMenuOpen = False
, subs = Sub.none
@ -127,6 +133,7 @@ init key url flags_ settings =
, Cmd.map CollSettingsMsg csc
, Cmd.map LoginMsg loginc
, Cmd.map ShareMsg shc
, Cmd.map ShareDetailMsg sdc
]
)
@ -170,6 +177,7 @@ type Msg
| NewInviteMsg Page.NewInvite.Data.Msg
| ItemDetailMsg Page.ItemDetail.Data.Msg
| ShareMsg Page.Share.Data.Msg
| ShareDetailMsg Page.ShareDetail.Data.Msg
| Logout
| LogoutResp (Result Http.Error ())
| SessionCheckResp (Result Http.Error AuthResult)

View File

@ -36,6 +36,8 @@ import Page.Register.Data
import Page.Register.Update
import Page.Share.Data
import Page.Share.Update
import Page.ShareDetail.Data
import Page.ShareDetail.Update
import Page.Upload.Data
import Page.Upload.Update
import Page.UserSettings.Data
@ -119,6 +121,9 @@ updateWithSub msg model =
ShareMsg lm ->
updateShare lm model
ShareDetailMsg lm ->
updateShareDetail lm model
LoginMsg lm ->
updateLogin lm model
@ -318,9 +323,26 @@ applyClientSettings model settings =
{ model | uiSettings = settings }
updateShareDetail : Page.ShareDetail.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateShareDetail lmsg model =
case Page.pageShareDetail model.page of
Just ( shareId, itemId ) ->
let
( m, c ) =
Page.ShareDetail.Update.update shareId itemId model.flags lmsg model.shareDetailModel
in
( { model | shareDetailModel = m }
, Cmd.map ShareDetailMsg c
, Sub.none
)
Nothing ->
( model, Cmd.none, Sub.none )
updateShare : Page.Share.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateShare lmsg model =
case Page.shareId model.page of
case Page.pageShareId model.page of
Just id ->
let
result =
@ -593,3 +615,15 @@ initPage model_ page =
SharePage _ ->
( model, Cmd.none, Sub.none )
ShareDetailPage _ _ ->
case model_.page of
SharePage _ ->
let
verifyResult =
model.shareModel.verifyResult
in
updateShareDetail (Page.ShareDetail.Data.VerifyResp (Ok verifyResult)) model
_ ->
( model, Cmd.none, Sub.none )

View File

@ -28,6 +28,7 @@ import Page.NewInvite.View2 as NewInvite
import Page.Queue.View2 as Queue
import Page.Register.View2 as Register
import Page.Share.View as Share
import Page.ShareDetail.View as ShareDetail
import Page.Upload.View2 as Upload
import Page.UserSettings.View2 as UserSettings
import Styles as S
@ -166,6 +167,9 @@ mainContent model =
SharePage id ->
viewShare texts id model
ShareDetailPage shareId itemId ->
viewShareDetail texts shareId itemId model
)
@ -434,11 +438,33 @@ viewShare texts shareId model =
model.flags
model.version
model.uiSettings
shareId
model.shareModel
)
]
viewShareDetail : Messages -> String -> String -> Model -> List (Html Msg)
viewShareDetail texts shareId itemId model =
[ Html.map ShareDetailMsg
(ShareDetail.viewSidebar texts.shareDetail
model.sidebarVisible
model.flags
model.uiSettings
model.shareDetailModel
)
, Html.map ShareDetailMsg
(ShareDetail.viewContent texts.shareDetail
model.flags
model.uiSettings
model.version
shareId
itemId
model.shareDetailModel
)
]
viewHome : Messages -> Model -> List (Html Msg)
viewHome texts model =
[ Html.map HomeMsg

View File

@ -59,6 +59,7 @@ type alias ViewConfig =
, previewUrl : AttachmentLight -> String
, previewUrlFallback : ItemLight -> String
, attachUrl : AttachmentLight -> String
, detailPage : ItemLight -> Page
}
@ -174,7 +175,7 @@ view2 texts cfg settings model item =
cardAction =
case cfg.selection of
Data.ItemSelection.Inactive ->
[ Page.href (ItemDetailPage item.id)
[ Page.href (cfg.detailPage item)
]
Data.ItemSelection.Active ids ->
@ -530,7 +531,7 @@ previewMenu2 texts settings cfg model item mainAttach =
, a
[ class S.secondaryBasicButtonPlain
, class "px-2 py-1 border rounded ml-2"
, Page.href (ItemDetailPage item.id)
, Page.href (cfg.detailPage item)
, title texts.gotoDetail
]
[ i [ class "fa fa-edit" ] []

View File

@ -165,6 +165,7 @@ type alias ViewConfig =
, previewUrl : AttachmentLight -> String
, previewUrlFallback : ItemLight -> String
, attachUrl : AttachmentLight -> String
, detailPage : ItemLight -> Page
}
@ -220,7 +221,7 @@ viewItem2 texts model cfg settings item =
""
vvcfg =
Comp.ItemCard.ViewConfig cfg.selection currentClass cfg.previewUrl cfg.previewUrlFallback cfg.attachUrl
Comp.ItemCard.ViewConfig cfg.selection currentClass cfg.previewUrl cfg.previewUrlFallback cfg.attachUrl cfg.detailPage
cardModel =
Dict.get item.id model.itemCards

View File

@ -0,0 +1,156 @@
module Comp.SharePasswordForm exposing (Model, Msg, init, update, view)
import Api
import Api.Model.ShareVerifyResult exposing (ShareVerifyResult)
import Api.Model.VersionInfo exposing (VersionInfo)
import Data.Flags exposing (Flags)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onInput, onSubmit)
import Http
import Messages.Comp.SharePasswordForm exposing (Texts)
import Styles as S
type CompError
= CompErrorNone
| CompErrorPasswordFailed
| CompErrorHttp Http.Error
type alias Model =
{ password : String
, compError : CompError
}
init : Model
init =
{ password = ""
, compError = CompErrorNone
}
type Msg
= SetPassword String
| SubmitPassword
| VerifyResp (Result Http.Error ShareVerifyResult)
--- update
update : String -> Flags -> Msg -> Model -> ( Model, Cmd Msg, Maybe ShareVerifyResult )
update shareId flags msg model =
case msg of
SetPassword pw ->
( { model | password = pw }, Cmd.none, Nothing )
SubmitPassword ->
let
secret =
{ shareId = shareId
, password = Just model.password
}
in
( model, Api.verifyShare flags secret VerifyResp, Nothing )
VerifyResp (Ok res) ->
if res.success then
( { model | password = "", compError = CompErrorNone }, Cmd.none, Just res )
else
( { model | password = "", compError = CompErrorPasswordFailed }, Cmd.none, Nothing )
VerifyResp (Err err) ->
( { model | password = "", compError = CompErrorHttp err }, Cmd.none, Nothing )
--- view
view : Texts -> Flags -> VersionInfo -> Model -> Html Msg
view texts flags versionInfo model =
div [ class "flex flex-col items-center" ]
[ div [ class ("flex flex-col px-4 sm:px-6 md:px-8 lg:px-10 py-8 rounded-md " ++ S.box) ]
[ div [ class "self-center" ]
[ img
[ class "w-16 py-2"
, src (flags.config.docspellAssetPath ++ "/img/logo-96.png")
]
[]
]
, div [ class "font-medium self-center text-xl sm:text-2xl" ]
[ text texts.passwordRequired
]
, Html.form
[ action "#"
, onSubmit SubmitPassword
, autocomplete False
]
[ div [ class "flex flex-col my-3" ]
[ label
[ for "password"
, class S.inputLabel
]
[ text texts.password
]
, div [ class "relative" ]
[ div [ class S.inputIcon ]
[ i [ class "fa fa-lock" ] []
]
, input
[ type_ "password"
, name "password"
, autocomplete False
, autofocus True
, tabindex 1
, onInput SetPassword
, value model.password
, class ("pl-10 pr-4 py-2 rounded-lg" ++ S.textInput)
, placeholder texts.password
]
[]
]
]
, div [ class "flex flex-col my-3" ]
[ button
[ type_ "submit"
, class S.primaryButton
]
[ text texts.passwordSubmitButton
]
]
, case model.compError of
CompErrorNone ->
span [ class "hidden" ] []
CompErrorHttp err ->
div [ class S.errorMessage ]
[ text (texts.httpError err)
]
CompErrorPasswordFailed ->
div [ class S.errorMessage ]
[ text texts.passwordFailed
]
]
]
, a
[ class "inline-flex items-center mt-4 text-xs opacity-50 hover:opacity-90"
, href "https://docspell.org"
, target "_new"
]
[ img
[ src (flags.config.docspellAssetPath ++ "/img/logo-mc-96.png")
, class "w-3 h-3 mr-1"
]
[]
, span []
[ text "Docspell "
, text versionInfo.version
]
]
]

View File

@ -22,6 +22,7 @@ import Messages.Page.NewInvite
import Messages.Page.Queue
import Messages.Page.Register
import Messages.Page.Share
import Messages.Page.ShareDetail
import Messages.Page.Upload
import Messages.Page.UserSettings
import Messages.UiLanguage exposing (UiLanguage(..))
@ -46,6 +47,7 @@ type alias Messages =
, manageData : Messages.Page.ManageData.Texts
, home : Messages.Page.Home.Texts
, share : Messages.Page.Share.Texts
, shareDetail : Messages.Page.ShareDetail.Texts
}
@ -112,6 +114,7 @@ gb =
, manageData = Messages.Page.ManageData.gb
, home = Messages.Page.Home.gb
, share = Messages.Page.Share.gb
, shareDetail = Messages.Page.ShareDetail.gb
}
@ -133,4 +136,5 @@ de =
, manageData = Messages.Page.ManageData.de
, home = Messages.Page.Home.de
, share = Messages.Page.Share.de
, shareDetail = Messages.Page.ShareDetail.de
}

View File

@ -0,0 +1,33 @@
module Messages.Comp.SharePasswordForm exposing (Texts, de, gb)
import Http
import Messages.Comp.HttpError
type alias Texts =
{ httpError : Http.Error -> String
, passwordRequired : String
, password : String
, passwordSubmitButton : String
, passwordFailed : String
}
gb : Texts
gb =
{ httpError = Messages.Comp.HttpError.gb
, passwordRequired = "Password required"
, password = "Password"
, passwordSubmitButton = "Submit"
, passwordFailed = "Das Passwort ist falsch"
}
de : Texts
de =
{ httpError = Messages.Comp.HttpError.de
, passwordRequired = "Passwort benötigt"
, password = "Passwort"
, passwordSubmitButton = "Submit"
, passwordFailed = "Password is wrong"
}

View File

@ -10,16 +10,14 @@ module Messages.Page.Share exposing (..)
import Messages.Basics
import Messages.Comp.ItemCardList
import Messages.Comp.SearchMenu
import Messages.Comp.SharePasswordForm
type alias Texts =
{ searchMenu : Messages.Comp.SearchMenu.Texts
, basics : Messages.Basics.Texts
, itemCardList : Messages.Comp.ItemCardList.Texts
, passwordRequired : String
, password : String
, passwordSubmitButton : String
, passwordFailed : String
, passwordForm : Messages.Comp.SharePasswordForm.Texts
}
@ -28,10 +26,7 @@ gb =
{ searchMenu = Messages.Comp.SearchMenu.gb
, basics = Messages.Basics.gb
, itemCardList = Messages.Comp.ItemCardList.gb
, passwordRequired = "Password required"
, password = "Password"
, passwordSubmitButton = "Submit"
, passwordFailed = "Das Passwort ist falsch"
, passwordForm = Messages.Comp.SharePasswordForm.gb
}
@ -40,8 +35,5 @@ de =
{ searchMenu = Messages.Comp.SearchMenu.de
, basics = Messages.Basics.de
, itemCardList = Messages.Comp.ItemCardList.de
, passwordRequired = "Passwort benötigt"
, password = "Passwort"
, passwordSubmitButton = "Submit"
, passwordFailed = "Password is wrong"
, passwordForm = Messages.Comp.SharePasswordForm.de
}

View File

@ -0,0 +1,20 @@
module Messages.Page.ShareDetail exposing (..)
import Messages.Comp.SharePasswordForm
type alias Texts =
{ passwordForm : Messages.Comp.SharePasswordForm.Texts
}
gb : Texts
gb =
{ passwordForm = Messages.Comp.SharePasswordForm.gb
}
de : Texts
de =
{ passwordForm = Messages.Comp.SharePasswordForm.de
}

View File

@ -19,9 +19,10 @@ module Page exposing
, loginPageReferrer
, pageFromString
, pageName
, pageShareDetail
, pageShareId
, pageToString
, set
, shareId
, uploadId
)
@ -61,6 +62,7 @@ type Page
| NewInvitePage
| ItemDetailPage String
| SharePage String
| ShareDetailPage String String
isSecured : Page -> Bool
@ -99,6 +101,9 @@ isSecured page =
SharePage _ ->
False
ShareDetailPage _ _ ->
False
{-| Currently, all secured pages have a sidebar, except UploadPage.
-}
@ -171,6 +176,9 @@ pageName page =
SharePage _ ->
"Share"
ShareDetailPage _ _ ->
"Share Detail"
loginPageReferrer : Page -> LoginData
loginPageReferrer page =
@ -182,8 +190,8 @@ loginPageReferrer page =
emptyLoginData
shareId : Page -> Maybe String
shareId page =
pageShareId : Page -> Maybe String
pageShareId page =
case page of
SharePage id ->
Just id
@ -192,6 +200,16 @@ shareId page =
Nothing
pageShareDetail : Page -> Maybe ( String, String )
pageShareDetail page =
case page of
ShareDetailPage shareId itemId ->
Just ( shareId, itemId )
_ ->
Nothing
uploadId : Page -> Maybe String
uploadId page =
case page of
@ -248,6 +266,9 @@ pageToString page =
SharePage id ->
"/app/share/" ++ id
ShareDetailPage shareId itemId ->
"/app/share/" ++ shareId ++ "/" ++ itemId
pageFromString : String -> Maybe Page
pageFromString str =
@ -304,6 +325,7 @@ parser =
, Parser.map (UploadPage Nothing) (s pathPrefix </> s "upload")
, Parser.map NewInvitePage (s pathPrefix </> s "newinvite")
, Parser.map ItemDetailPage (s pathPrefix </> s "item" </> string)
, Parser.map ShareDetailPage (s pathPrefix </> s "share" </> string </> string)
, Parser.map SharePage (s pathPrefix </> s "share" </> string)
]

View File

@ -468,23 +468,22 @@ itemCardList texts _ settings model =
previewUrlFallback item =
Api.itemBasePreviewURL item.id
viewCfg sel =
Comp.ItemCardList.ViewConfig
model.scrollToCard
sel
previewUrl
previewUrlFallback
(.id >> Api.fileURL)
(.id >> ItemDetailPage)
itemViewCfg =
case model.viewMode of
SelectView svm ->
Comp.ItemCardList.ViewConfig
model.scrollToCard
(Data.ItemSelection.Active svm.ids)
previewUrl
previewUrlFallback
(.id >> Api.fileURL)
viewCfg (Data.ItemSelection.Active svm.ids)
_ ->
Comp.ItemCardList.ViewConfig
model.scrollToCard
Data.ItemSelection.Inactive
previewUrl
previewUrlFallback
(.id >> Api.fileURL)
viewCfg Data.ItemSelection.Inactive
in
[ Html.map ItemCardListMsg
(Comp.ItemCardList.view2 texts.itemCardList

View File

@ -15,6 +15,7 @@ import Api.Model.ShareVerifyResult exposing (ShareVerifyResult)
import Comp.ItemCardList
import Comp.PowerSearchInput
import Comp.SearchMenu
import Comp.SharePasswordForm
import Data.Flags exposing (Flags)
import Http
@ -31,16 +32,10 @@ type PageError
| PageErrorAuthFail
type alias PasswordModel =
{ password : String
, passwordFailed : Bool
}
type alias Model =
{ mode : Mode
, verifyResult : ShareVerifyResult
, passwordModel : PasswordModel
, passwordModel : Comp.SharePasswordForm.Model
, pageError : PageError
, searchMenuModel : Comp.SearchMenu.Model
, powerSearchInput : Comp.PowerSearchInput.Model
@ -53,10 +48,7 @@ emptyModel : Flags -> Model
emptyModel flags =
{ mode = ModeInitial
, verifyResult = Api.Model.ShareVerifyResult.empty
, passwordModel =
{ password = ""
, passwordFailed = False
}
, passwordModel = Comp.SharePasswordForm.init
, pageError = PageErrorNone
, searchMenuModel = Comp.SearchMenu.init flags
, powerSearchInput = Comp.PowerSearchInput.init
@ -79,8 +71,7 @@ type Msg
= VerifyResp (Result Http.Error ShareVerifyResult)
| SearchResp (Result Http.Error ItemLightList)
| StatsResp (Result Http.Error SearchStats)
| SetPassword String
| SubmitPassword
| PasswordMsg Comp.SharePasswordForm.Msg
| SearchMenuMsg Comp.SearchMenu.Msg
| PowerSearchMsg Comp.PowerSearchInput.Msg
| ResetSearch

View File

@ -14,11 +14,12 @@ import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
import Messages.Page.Share exposing (Texts)
import Page exposing (Page(..))
import Page.Share.Data exposing (Model, Msg(..))
view : Texts -> UiSettings -> Model -> Html Msg
view texts settings model =
view : Texts -> UiSettings -> String -> Model -> Html Msg
view texts settings shareId model =
let
viewCfg =
{ current = Nothing
@ -26,6 +27,7 @@ view texts settings model =
, previewUrl = \attach -> Api.shareAttachmentPreviewURL attach.id
, previewUrlFallback = \item -> Api.shareItemBasePreviewURL item.id
, attachUrl = .id >> Api.shareFileURL
, detailPage = \item -> ShareDetailPage shareId item.id
}
in
div []

View File

@ -13,6 +13,7 @@ import Comp.ItemCardList
import Comp.LinkTarget exposing (LinkTarget)
import Comp.PowerSearchInput
import Comp.SearchMenu
import Comp.SharePasswordForm
import Data.Flags exposing (Flags)
import Data.ItemQuery as Q
import Data.SearchMode
@ -51,26 +52,13 @@ update flags settings shareId msg model =
)
else if res.passwordRequired then
if model.mode == ModePassword then
noSub
( { model
| pageError = PageErrorNone
, passwordModel =
{ password = ""
, passwordFailed = True
}
}
, Cmd.none
)
else
noSub
( { model
| pageError = PageErrorNone
, mode = ModePassword
}
, Cmd.none
)
noSub
( { model
| pageError = PageErrorNone
, mode = ModePassword
}
, Cmd.none
)
else
noSub
@ -101,21 +89,21 @@ update flags settings shareId msg model =
StatsResp (Err err) ->
noSub ( { model | pageError = PageErrorHttp err }, Cmd.none )
SetPassword pw ->
PasswordMsg lmsg ->
let
pm =
model.passwordModel
( m, c, res ) =
Comp.SharePasswordForm.update shareId flags lmsg model.passwordModel
in
noSub ( { model | passwordModel = { pm | password = pw } }, Cmd.none )
case res of
Just verifyResult ->
update flags
settings
shareId
(VerifyResp (Ok verifyResult))
model
SubmitPassword ->
let
secret =
{ shareId = shareId
, password = Just model.passwordModel.password
}
in
noSub ( model, Api.verifyShare flags secret VerifyResp )
Nothing ->
noSub ( { model | passwordModel = m }, Cmd.map PasswordMsg c )
SearchMenuMsg lm ->
let

View File

@ -9,6 +9,7 @@ module Page.Share.View exposing (viewContent, viewSidebar)
import Api.Model.VersionInfo exposing (VersionInfo)
import Comp.Basic as B
import Comp.SharePasswordForm
import Data.Flags exposing (Flags)
import Data.Items
import Data.UiSettings exposing (UiSettings)
@ -35,8 +36,8 @@ viewSidebar texts visible flags settings model =
]
viewContent : Texts -> Flags -> VersionInfo -> UiSettings -> Model -> Html Msg
viewContent texts flags versionInfo uiSettings model =
viewContent : Texts -> Flags -> VersionInfo -> UiSettings -> String -> Model -> Html Msg
viewContent texts flags versionInfo uiSettings shareId model =
case model.mode of
ModeInitial ->
div
@ -54,15 +55,15 @@ viewContent texts flags versionInfo uiSettings model =
passwordContent texts flags versionInfo model
ModeShare ->
mainContent texts flags uiSettings model
mainContent texts flags uiSettings shareId model
--- Helpers
mainContent : Texts -> Flags -> UiSettings -> Model -> Html Msg
mainContent texts _ settings model =
mainContent : Texts -> Flags -> UiSettings -> String -> Model -> Html Msg
mainContent texts _ settings shareId model =
div
[ id "content"
, class "h-full flex flex-col"
@ -75,7 +76,7 @@ mainContent texts _ settings model =
[ text <| Maybe.withDefault "" model.verifyResult.name
]
, Menubar.view texts model
, Results.view texts settings model
, Results.view texts settings shareId model
]
@ -86,76 +87,6 @@ passwordContent texts flags versionInfo model =
, class "h-full flex flex-col items-center justify-center w-full"
, class S.content
]
[ div [ class ("flex flex-col px-4 sm:px-6 md:px-8 lg:px-10 py-8 rounded-md " ++ S.box) ]
[ div [ class "self-center" ]
[ img
[ class "w-16 py-2"
, src (flags.config.docspellAssetPath ++ "/img/logo-96.png")
]
[]
]
, div [ class "font-medium self-center text-xl sm:text-2xl" ]
[ text texts.passwordRequired
]
, Html.form
[ action "#"
, onSubmit SubmitPassword
, autocomplete False
]
[ div [ class "flex flex-col my-3" ]
[ label
[ for "password"
, class S.inputLabel
]
[ text texts.password
]
, div [ class "relative" ]
[ div [ class S.inputIcon ]
[ i [ class "fa fa-lock" ] []
]
, input
[ type_ "password"
, name "password"
, autocomplete False
, autofocus True
, tabindex 1
, onInput SetPassword
, value model.passwordModel.password
, class ("pl-10 pr-4 py-2 rounded-lg" ++ S.textInput)
, placeholder texts.password
]
[]
]
]
, div [ class "flex flex-col my-3" ]
[ button
[ type_ "submit"
, class S.primaryButton
]
[ text texts.passwordSubmitButton
]
]
, div
[ class S.errorMessage
, classList [ ( "hidden", not model.passwordModel.passwordFailed ) ]
]
[ text texts.passwordFailed
]
]
]
, a
[ class "inline-flex items-center mt-4 text-xs opacity-50 hover:opacity-90"
, href "https://docspell.org"
, target "_new"
]
[ img
[ src (flags.config.docspellAssetPath ++ "/img/logo-mc-96.png")
, class "w-3 h-3 mr-1"
]
[]
, span []
[ text "Docspell "
, text versionInfo.version
]
]
[ Html.map PasswordMsg
(Comp.SharePasswordForm.view texts.passwordForm flags versionInfo model.passwordModel)
]

View File

@ -0,0 +1,56 @@
module Page.ShareDetail.Data exposing (Model, Msg(..), PageError(..), ViewMode(..), init)
import Api
import Api.Model.ItemDetail exposing (ItemDetail)
import Api.Model.ShareSecret exposing (ShareSecret)
import Api.Model.ShareVerifyResult exposing (ShareVerifyResult)
import Comp.SharePasswordForm
import Data.Flags exposing (Flags)
import Http
type ViewMode
= ViewNormal
| ViewPassword
| ViewLoading
type PageError
= PageErrorNone
| PageErrorHttp Http.Error
| PageErrorAuthFail
type alias Model =
{ item : ItemDetail
, verifyResult : ShareVerifyResult
, passwordModel : Comp.SharePasswordForm.Model
, viewMode : ViewMode
, pageError : PageError
}
type Msg
= VerifyResp (Result Http.Error ShareVerifyResult)
| GetItemResp (Result Http.Error ItemDetail)
| PasswordMsg Comp.SharePasswordForm.Msg
emptyModel : ViewMode -> Model
emptyModel vm =
{ item = Api.Model.ItemDetail.empty
, verifyResult = Api.Model.ShareVerifyResult.empty
, passwordModel = Comp.SharePasswordForm.init
, viewMode = vm
, pageError = PageErrorNone
}
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 )
Nothing ->
( emptyModel ViewLoading, Cmd.none )

View File

@ -0,0 +1,64 @@
module Page.ShareDetail.Update exposing (update)
import Api
import Comp.SharePasswordForm
import Data.Flags exposing (Flags)
import Page.ShareDetail.Data exposing (..)
update : String -> String -> Flags -> Msg -> Model -> ( Model, Cmd Msg )
update shareId itemId flags msg model =
case msg of
VerifyResp (Ok res) ->
if res.success then
( { model
| pageError = PageErrorNone
, viewMode = ViewLoading
, verifyResult = res
}
, Api.itemDetailShare flags res.token itemId GetItemResp
)
else if res.passwordRequired then
( { model
| pageError = PageErrorNone
, viewMode = ViewPassword
}
, Cmd.none
)
else
( { model | pageError = PageErrorAuthFail }
, Cmd.none
)
VerifyResp (Err err) ->
( { model | pageError = PageErrorHttp err }, Cmd.none )
GetItemResp (Ok item) ->
( { model
| item = item
, viewMode = ViewNormal
, pageError = PageErrorNone
}
, Cmd.none
)
GetItemResp (Err err) ->
( { model | viewMode = ViewNormal, pageError = PageErrorHttp err }, Cmd.none )
PasswordMsg lmsg ->
let
( m, c, res ) =
Comp.SharePasswordForm.update shareId flags lmsg model.passwordModel
in
case res of
Just verifyResult ->
update shareId
itemId
flags
(VerifyResp (Ok verifyResult))
model
Nothing ->
( { model | passwordModel = m }, Cmd.map PasswordMsg c )

View File

@ -0,0 +1,108 @@
module Page.ShareDetail.View exposing (viewContent, viewSidebar)
import Api.Model.VersionInfo exposing (VersionInfo)
import Comp.Basic as B
import Comp.SharePasswordForm
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
import Messages.Page.ShareDetail exposing (Texts)
import Page exposing (Page(..))
import Page.ShareDetail.Data exposing (..)
import Styles as S
viewSidebar : Texts -> Bool -> Flags -> UiSettings -> Model -> Html Msg
viewSidebar texts visible flags settings model =
div
[ id "sidebar"
, class "hidden"
]
[]
viewContent : Texts -> Flags -> UiSettings -> VersionInfo -> String -> String -> Model -> Html Msg
viewContent texts flags uiSettings versionInfo shareId itemId model =
case model.viewMode of
ViewLoading ->
div
[ id "content"
, class "h-full w-full flex flex-col text-5xl"
, class S.content
]
[ B.loadingDimmer
{ active = model.pageError == PageErrorNone
, label = ""
}
]
ViewPassword ->
passwordContent texts flags versionInfo model
ViewNormal ->
mainContent texts flags uiSettings shareId model
--- Helper
mainContent : Texts -> Flags -> UiSettings -> String -> Model -> Html Msg
mainContent texts flags settings shareId model =
div
[ class "flex flex-col"
, class S.content
]
[ itemHead texts shareId model
, div [ class "flex flex-col sm:flex-row" ]
[ itemData texts model
, itemPreview texts flags settings model
]
]
itemData : Texts -> Model -> Html Msg
itemData texts model =
div [ class "flex" ]
[]
{-| Using ItemDetail Model to be able to reuse SingleAttachment component
-}
itemPreview : Texts -> Flags -> UiSettings -> Model -> Html Msg
itemPreview texts flags settings model =
div [ class "flex flex-grow" ]
[]
itemHead : Texts -> String -> Model -> Html Msg
itemHead texts shareId model =
div [ class "flex flex-col sm:flex-row" ]
[ div [ class "flex flex-grow items-center" ]
[ h1 [ class S.header1 ]
[ text model.item.name
]
]
, div [ class "flex flex-row items-center justify-end" ]
[ B.secondaryBasicButton
{ label = "Close"
, icon = "fa fa-times"
, disabled = False
, handler = Page.href (SharePage shareId)
, attrs = []
}
]
]
passwordContent : Texts -> Flags -> VersionInfo -> Model -> Html Msg
passwordContent texts flags versionInfo model =
div
[ id "content"
, class "h-full flex flex-col items-center justify-center w-full"
, class S.content
]
[ Html.map PasswordMsg
(Comp.SharePasswordForm.view texts.passwordForm flags versionInfo model.passwordModel)
]

View File

@ -14,6 +14,7 @@ module Util.Http exposing
, authTask
, executeIn
, jsonResolver
, shareGet
, sharePost
)
@ -167,6 +168,24 @@ authGet req =
}
shareGet :
{ url : String
, token : String
, expect : Http.Expect msg
}
-> Cmd msg
shareGet req =
shareReq
{ url = req.url
, token = req.token
, body = Http.emptyBody
, expect = req.expect
, method = "GET"
, headers = []
, tracker = Nothing
}
authDelete :
{ url : String
, account : AuthResult