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 , initOtp
, itemBasePreviewURL , itemBasePreviewURL
, itemDetail , itemDetail
, itemDetailShare
, itemIndexSearch , itemIndexSearch
, itemSearch , itemSearch
, itemSearchStats , 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 : String -> String
shareAttachmentPreviewURL id = shareAttachmentPreviewURL id =
"/api/v1/share/attachment/" ++ id ++ "/preview?withFallback=true" "/api/v1/share/attachment/" ++ id ++ "/preview?withFallback=true"

View File

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

View File

@ -36,6 +36,8 @@ import Page.Register.Data
import Page.Register.Update import Page.Register.Update
import Page.Share.Data import Page.Share.Data
import Page.Share.Update import Page.Share.Update
import Page.ShareDetail.Data
import Page.ShareDetail.Update
import Page.Upload.Data import Page.Upload.Data
import Page.Upload.Update import Page.Upload.Update
import Page.UserSettings.Data import Page.UserSettings.Data
@ -119,6 +121,9 @@ updateWithSub msg model =
ShareMsg lm -> ShareMsg lm ->
updateShare lm model updateShare lm model
ShareDetailMsg lm ->
updateShareDetail lm model
LoginMsg lm -> LoginMsg lm ->
updateLogin lm model updateLogin lm model
@ -318,9 +323,26 @@ applyClientSettings model settings =
{ model | uiSettings = 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 : Page.Share.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateShare lmsg model = updateShare lmsg model =
case Page.shareId model.page of case Page.pageShareId model.page of
Just id -> Just id ->
let let
result = result =
@ -593,3 +615,15 @@ initPage model_ page =
SharePage _ -> SharePage _ ->
( model, Cmd.none, Sub.none ) ( 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.Queue.View2 as Queue
import Page.Register.View2 as Register import Page.Register.View2 as Register
import Page.Share.View as Share import Page.Share.View as Share
import Page.ShareDetail.View as ShareDetail
import Page.Upload.View2 as Upload import Page.Upload.View2 as Upload
import Page.UserSettings.View2 as UserSettings import Page.UserSettings.View2 as UserSettings
import Styles as S import Styles as S
@ -166,6 +167,9 @@ mainContent model =
SharePage id -> SharePage id ->
viewShare texts id model viewShare texts id model
ShareDetailPage shareId itemId ->
viewShareDetail texts shareId itemId model
) )
@ -434,11 +438,33 @@ viewShare texts shareId model =
model.flags model.flags
model.version model.version
model.uiSettings model.uiSettings
shareId
model.shareModel 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 : Messages -> Model -> List (Html Msg)
viewHome texts model = viewHome texts model =
[ Html.map HomeMsg [ Html.map HomeMsg

View File

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

View File

@ -165,6 +165,7 @@ type alias ViewConfig =
, previewUrl : AttachmentLight -> String , previewUrl : AttachmentLight -> String
, previewUrlFallback : ItemLight -> String , previewUrlFallback : ItemLight -> String
, attachUrl : AttachmentLight -> String , attachUrl : AttachmentLight -> String
, detailPage : ItemLight -> Page
} }
@ -220,7 +221,7 @@ viewItem2 texts model cfg settings item =
"" ""
vvcfg = 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 = cardModel =
Dict.get item.id model.itemCards 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.Queue
import Messages.Page.Register import Messages.Page.Register
import Messages.Page.Share import Messages.Page.Share
import Messages.Page.ShareDetail
import Messages.Page.Upload import Messages.Page.Upload
import Messages.Page.UserSettings import Messages.Page.UserSettings
import Messages.UiLanguage exposing (UiLanguage(..)) import Messages.UiLanguage exposing (UiLanguage(..))
@ -46,6 +47,7 @@ type alias Messages =
, manageData : Messages.Page.ManageData.Texts , manageData : Messages.Page.ManageData.Texts
, home : Messages.Page.Home.Texts , home : Messages.Page.Home.Texts
, share : Messages.Page.Share.Texts , share : Messages.Page.Share.Texts
, shareDetail : Messages.Page.ShareDetail.Texts
} }
@ -112,6 +114,7 @@ gb =
, manageData = Messages.Page.ManageData.gb , manageData = Messages.Page.ManageData.gb
, home = Messages.Page.Home.gb , home = Messages.Page.Home.gb
, share = Messages.Page.Share.gb , share = Messages.Page.Share.gb
, shareDetail = Messages.Page.ShareDetail.gb
} }
@ -133,4 +136,5 @@ de =
, manageData = Messages.Page.ManageData.de , manageData = Messages.Page.ManageData.de
, home = Messages.Page.Home.de , home = Messages.Page.Home.de
, share = Messages.Page.Share.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.Basics
import Messages.Comp.ItemCardList import Messages.Comp.ItemCardList
import Messages.Comp.SearchMenu import Messages.Comp.SearchMenu
import Messages.Comp.SharePasswordForm
type alias Texts = type alias Texts =
{ searchMenu : Messages.Comp.SearchMenu.Texts { searchMenu : Messages.Comp.SearchMenu.Texts
, basics : Messages.Basics.Texts , basics : Messages.Basics.Texts
, itemCardList : Messages.Comp.ItemCardList.Texts , itemCardList : Messages.Comp.ItemCardList.Texts
, passwordRequired : String , passwordForm : Messages.Comp.SharePasswordForm.Texts
, password : String
, passwordSubmitButton : String
, passwordFailed : String
} }
@ -28,10 +26,7 @@ gb =
{ searchMenu = Messages.Comp.SearchMenu.gb { searchMenu = Messages.Comp.SearchMenu.gb
, basics = Messages.Basics.gb , basics = Messages.Basics.gb
, itemCardList = Messages.Comp.ItemCardList.gb , itemCardList = Messages.Comp.ItemCardList.gb
, passwordRequired = "Password required" , passwordForm = Messages.Comp.SharePasswordForm.gb
, password = "Password"
, passwordSubmitButton = "Submit"
, passwordFailed = "Das Passwort ist falsch"
} }
@ -40,8 +35,5 @@ de =
{ searchMenu = Messages.Comp.SearchMenu.de { searchMenu = Messages.Comp.SearchMenu.de
, basics = Messages.Basics.de , basics = Messages.Basics.de
, itemCardList = Messages.Comp.ItemCardList.de , itemCardList = Messages.Comp.ItemCardList.de
, passwordRequired = "Passwort benötigt" , passwordForm = Messages.Comp.SharePasswordForm.de
, password = "Passwort"
, passwordSubmitButton = "Submit"
, passwordFailed = "Password is wrong"
} }

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,6 +9,7 @@ module Page.Share.View exposing (viewContent, viewSidebar)
import Api.Model.VersionInfo exposing (VersionInfo) import Api.Model.VersionInfo exposing (VersionInfo)
import Comp.Basic as B import Comp.Basic as B
import Comp.SharePasswordForm
import Data.Flags exposing (Flags) import Data.Flags exposing (Flags)
import Data.Items import Data.Items
import Data.UiSettings exposing (UiSettings) 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 -> String -> Model -> Html Msg
viewContent texts flags versionInfo uiSettings model = viewContent texts flags versionInfo uiSettings shareId model =
case model.mode of case model.mode of
ModeInitial -> ModeInitial ->
div div
@ -54,15 +55,15 @@ viewContent texts flags versionInfo uiSettings model =
passwordContent texts flags versionInfo model passwordContent texts flags versionInfo model
ModeShare -> ModeShare ->
mainContent texts flags uiSettings model mainContent texts flags uiSettings shareId model
--- Helpers --- Helpers
mainContent : Texts -> Flags -> UiSettings -> Model -> Html Msg mainContent : Texts -> Flags -> UiSettings -> String -> Model -> Html Msg
mainContent texts _ settings model = mainContent texts _ settings shareId model =
div div
[ id "content" [ id "content"
, class "h-full flex flex-col" , class "h-full flex flex-col"
@ -75,7 +76,7 @@ mainContent texts _ settings model =
[ text <| Maybe.withDefault "" model.verifyResult.name [ text <| Maybe.withDefault "" model.verifyResult.name
] ]
, Menubar.view texts model , 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 "h-full flex flex-col items-center justify-center w-full"
, class S.content , 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) ] [ Html.map PasswordMsg
[ div [ class "self-center" ] (Comp.SharePasswordForm.view texts.passwordForm flags versionInfo model.passwordModel)
[ 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
]
]
] ]

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 , authTask
, executeIn , executeIn
, jsonResolver , jsonResolver
, shareGet
, sharePost , 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 : authDelete :
{ url : String { url : String
, account : AuthResult , account : AuthResult