mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-03-25 16:45:05 +00:00
Improve item detail view
- Separate page (permalink) for item details - Use available space and hide search menu - Disable item navigation links if there is nothing to go to - Show notes more prominently and allow to hide them
This commit is contained in:
parent
36a6fdd746
commit
c73cdd82ab
@ -15,6 +15,7 @@ import Http
|
||||
import Page exposing (Page(..))
|
||||
import Page.CollectiveSettings.Data
|
||||
import Page.Home.Data
|
||||
import Page.ItemDetail.Data
|
||||
import Page.Login.Data
|
||||
import Page.ManageData.Data
|
||||
import Page.NewInvite.Data
|
||||
@ -39,6 +40,7 @@ type alias Model =
|
||||
, registerModel : Page.Register.Data.Model
|
||||
, uploadModel : Page.Upload.Data.Model
|
||||
, newInviteModel : Page.NewInvite.Data.Model
|
||||
, itemDetailModel : Page.ItemDetail.Data.Model
|
||||
, navMenuOpen : Bool
|
||||
, subs : Sub Msg
|
||||
}
|
||||
@ -64,6 +66,7 @@ init key url flags =
|
||||
, registerModel = Page.Register.Data.emptyModel
|
||||
, uploadModel = Page.Upload.Data.emptyModel
|
||||
, newInviteModel = Page.NewInvite.Data.emptyModel
|
||||
, itemDetailModel = Page.ItemDetail.Data.emptyModel
|
||||
, navMenuOpen = False
|
||||
, subs = Sub.none
|
||||
}
|
||||
@ -82,6 +85,7 @@ type Msg
|
||||
| RegisterMsg Page.Register.Data.Msg
|
||||
| UploadMsg Page.Upload.Data.Msg
|
||||
| NewInviteMsg Page.NewInvite.Data.Msg
|
||||
| ItemDetailMsg Page.ItemDetail.Data.Msg
|
||||
| Logout
|
||||
| LogoutResp (Result Http.Error ())
|
||||
| SessionCheckResp (Result Http.Error AuthResult)
|
||||
|
@ -13,6 +13,8 @@ import Page.CollectiveSettings.Data
|
||||
import Page.CollectiveSettings.Update
|
||||
import Page.Home.Data
|
||||
import Page.Home.Update
|
||||
import Page.ItemDetail.Data
|
||||
import Page.ItemDetail.Update
|
||||
import Page.Login.Data
|
||||
import Page.Login.Update
|
||||
import Page.ManageData.Data
|
||||
@ -71,6 +73,9 @@ updateWithSub msg model =
|
||||
NewInviteMsg m ->
|
||||
updateNewInvite m model |> noSub
|
||||
|
||||
ItemDetailMsg m ->
|
||||
updateItemDetail m model |> noSub
|
||||
|
||||
VersionResp (Ok info) ->
|
||||
( { model | version = info }, Cmd.none ) |> noSub
|
||||
|
||||
@ -170,6 +175,20 @@ updateWithSub msg model =
|
||||
( { model | navMenuOpen = not model.navMenuOpen }, Cmd.none, Sub.none )
|
||||
|
||||
|
||||
updateItemDetail : Page.ItemDetail.Data.Msg -> Model -> ( Model, Cmd Msg )
|
||||
updateItemDetail lmsg model =
|
||||
let
|
||||
inav =
|
||||
Page.Home.Data.itemNav model.itemDetailModel.detail.item.id model.homeModel
|
||||
|
||||
( lm, lc ) =
|
||||
Page.ItemDetail.Update.update model.key model.flags inav.next lmsg model.itemDetailModel
|
||||
in
|
||||
( { model | itemDetailModel = lm }
|
||||
, Cmd.map ItemDetailMsg lc
|
||||
)
|
||||
|
||||
|
||||
updateNewInvite : Page.NewInvite.Data.Msg -> Model -> ( Model, Cmd Msg )
|
||||
updateNewInvite lmsg model =
|
||||
let
|
||||
@ -265,7 +284,7 @@ updateHome : Page.Home.Data.Msg -> Model -> ( Model, Cmd Msg )
|
||||
updateHome lmsg model =
|
||||
let
|
||||
( lm, lc ) =
|
||||
Page.Home.Update.update model.flags lmsg model.homeModel
|
||||
Page.Home.Update.update model.key model.flags lmsg model.homeModel
|
||||
in
|
||||
( { model | homeModel = lm }
|
||||
, Cmd.map HomeMsg lc
|
||||
@ -321,6 +340,9 @@ initPage model page =
|
||||
NewInvitePage ->
|
||||
updateQueue Page.Queue.Data.StopRefresh model
|
||||
|
||||
ItemDetailPage id ->
|
||||
updateItemDetail (Page.ItemDetail.Data.Init id) model
|
||||
|
||||
|
||||
noSub : ( Model, Cmd Msg ) -> ( Model, Cmd Msg, Sub Msg )
|
||||
noSub ( m, c ) =
|
||||
|
@ -6,7 +6,9 @@ import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Page exposing (Page(..))
|
||||
import Page.CollectiveSettings.View
|
||||
import Page.Home.Data
|
||||
import Page.Home.View
|
||||
import Page.ItemDetail.View
|
||||
import Page.Login.View
|
||||
import Page.ManageData.View
|
||||
import Page.NewInvite.View
|
||||
@ -105,11 +107,23 @@ defaultLayout model =
|
||||
|
||||
NewInvitePage ->
|
||||
viewNewInvite model
|
||||
|
||||
ItemDetailPage id ->
|
||||
viewItemDetail id model
|
||||
]
|
||||
, footer model
|
||||
]
|
||||
|
||||
|
||||
viewItemDetail : String -> Model -> Html Msg
|
||||
viewItemDetail id model =
|
||||
let
|
||||
inav =
|
||||
Page.Home.Data.itemNav id model.homeModel
|
||||
in
|
||||
Html.map ItemDetailMsg (Page.ItemDetail.View.view inav model.itemDetailModel)
|
||||
|
||||
|
||||
viewNewInvite : Model -> Html Msg
|
||||
viewNewInvite model =
|
||||
Html.map NewInviteMsg (Page.NewInvite.View.view model.flags model.newInviteModel)
|
||||
|
@ -1,7 +1,6 @@
|
||||
module Comp.ItemDetail exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, UserNav(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
@ -20,6 +19,7 @@ import Api.Model.OptionalText exposing (OptionalText)
|
||||
import Api.Model.ReferenceList exposing (ReferenceList)
|
||||
import Api.Model.Tag exposing (Tag)
|
||||
import Api.Model.TagList exposing (TagList)
|
||||
import Browser.Navigation as Nav
|
||||
import Comp.DatePicker
|
||||
import Comp.Dropdown exposing (isDropdownChangeMsg)
|
||||
import Comp.YesNoDimmer
|
||||
@ -31,6 +31,7 @@ import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onInput)
|
||||
import Http
|
||||
import Markdown
|
||||
import Page exposing (Page(..))
|
||||
import Util.Maybe
|
||||
import Util.Size
|
||||
import Util.String
|
||||
@ -49,6 +50,7 @@ type alias Model =
|
||||
, concEquipModel : Comp.Dropdown.Model IdName
|
||||
, nameModel : String
|
||||
, notesModel : Maybe String
|
||||
, notesHidden : Bool
|
||||
, deleteConfirm : Comp.YesNoDimmer.Model
|
||||
, itemDatePicker : DatePicker
|
||||
, itemDate : Maybe Int
|
||||
@ -76,7 +78,11 @@ emptyModel =
|
||||
}
|
||||
, directionModel =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \entry -> { value = Data.Direction.toString entry, text = Data.Direction.toString entry }
|
||||
{ makeOption =
|
||||
\entry ->
|
||||
{ value = Data.Direction.toString entry
|
||||
, text = Data.Direction.toString entry
|
||||
}
|
||||
, options = Data.Direction.all
|
||||
, placeholder = "Choose a direction…"
|
||||
, selected = Nothing
|
||||
@ -103,6 +109,7 @@ emptyModel =
|
||||
}
|
||||
, nameModel = ""
|
||||
, notesModel = Nothing
|
||||
, notesHidden = False
|
||||
, deleteConfirm = Comp.YesNoDimmer.emptyModel
|
||||
, itemDatePicker = Comp.DatePicker.emptyModel
|
||||
, itemDate = Nothing
|
||||
@ -112,26 +119,12 @@ emptyModel =
|
||||
}
|
||||
|
||||
|
||||
type UserNav
|
||||
= NavBack
|
||||
| NavPrev
|
||||
| NavNext
|
||||
| NavNone
|
||||
| NavNextOrBack
|
||||
|
||||
|
||||
noNav : ( Model, Cmd Msg ) -> ( Model, Cmd Msg, UserNav )
|
||||
noNav ( model, cmd ) =
|
||||
( model, cmd, NavNone )
|
||||
|
||||
|
||||
type Msg
|
||||
= ToggleMenu
|
||||
| ReloadItem
|
||||
| Init
|
||||
| SetItem ItemDetail
|
||||
| SetActiveAttachment Int
|
||||
| NavClick UserNav
|
||||
| TagDropdownMsg (Comp.Dropdown.Msg Tag)
|
||||
| DirDropdownMsg (Comp.Dropdown.Msg Direction)
|
||||
| OrgDropdownMsg (Comp.Dropdown.Msg IdName)
|
||||
@ -145,6 +138,7 @@ type Msg
|
||||
| SetName String
|
||||
| SaveName
|
||||
| SetNotes String
|
||||
| ToggleNotes
|
||||
| SaveNotes
|
||||
| ConfirmItem
|
||||
| UnconfirmItem
|
||||
@ -281,8 +275,8 @@ setDueDate flags model date =
|
||||
Api.setItemDueDate flags model.item.id (OptionalDate date) SaveResp
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg, UserNav )
|
||||
update flags msg model =
|
||||
update : Nav.Key -> Flags -> Maybe String -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update key flags next msg model =
|
||||
case msg of
|
||||
Init ->
|
||||
let
|
||||
@ -295,16 +289,17 @@ update flags msg model =
|
||||
, Cmd.map ItemDatePickerMsg dpc
|
||||
, Cmd.map DueDatePickerMsg dpc
|
||||
]
|
||||
, NavNone
|
||||
)
|
||||
|
||||
SetItem item ->
|
||||
let
|
||||
( m1, c1, _ ) =
|
||||
update flags (TagDropdownMsg (Comp.Dropdown.SetSelection item.tags)) model
|
||||
( m1, c1 ) =
|
||||
update key flags next (TagDropdownMsg (Comp.Dropdown.SetSelection item.tags)) model
|
||||
|
||||
( m2, c2, _ ) =
|
||||
update flags
|
||||
( m2, c2 ) =
|
||||
update key
|
||||
flags
|
||||
next
|
||||
(DirDropdownMsg
|
||||
(Comp.Dropdown.SetSelection
|
||||
(Data.Direction.fromString item.direction
|
||||
@ -315,8 +310,10 @@ update flags msg model =
|
||||
)
|
||||
m1
|
||||
|
||||
( m3, c3, _ ) =
|
||||
update flags
|
||||
( m3, c3 ) =
|
||||
update key
|
||||
flags
|
||||
next
|
||||
(OrgDropdownMsg
|
||||
(Comp.Dropdown.SetSelection
|
||||
(item.corrOrg
|
||||
@ -327,8 +324,10 @@ update flags msg model =
|
||||
)
|
||||
m2
|
||||
|
||||
( m4, c4, _ ) =
|
||||
update flags
|
||||
( m4, c4 ) =
|
||||
update key
|
||||
flags
|
||||
next
|
||||
(CorrPersonMsg
|
||||
(Comp.Dropdown.SetSelection
|
||||
(item.corrPerson
|
||||
@ -339,8 +338,10 @@ update flags msg model =
|
||||
)
|
||||
m3
|
||||
|
||||
( m5, c5, _ ) =
|
||||
update flags
|
||||
( m5, c5 ) =
|
||||
update key
|
||||
flags
|
||||
next
|
||||
(ConcPersonMsg
|
||||
(Comp.Dropdown.SetSelection
|
||||
(item.concPerson
|
||||
@ -358,26 +359,28 @@ update flags msg model =
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
( { m5 | item = item, nameModel = item.name, notesModel = item.notes, itemDate = item.itemDate, dueDate = item.dueDate }
|
||||
( { m5
|
||||
| item = item
|
||||
, nameModel = item.name
|
||||
, notesModel = item.notes
|
||||
, itemDate = item.itemDate
|
||||
, dueDate = item.dueDate
|
||||
}
|
||||
, Cmd.batch [ c1, c2, c3, c4, c5, getOptions flags, proposalCmd ]
|
||||
)
|
||||
|> noNav
|
||||
|
||||
SetActiveAttachment pos ->
|
||||
( { model | visibleAttach = pos }, Cmd.none, NavNone )
|
||||
|
||||
NavClick nav ->
|
||||
( model, Cmd.none, nav )
|
||||
( { model | visibleAttach = pos }, Cmd.none )
|
||||
|
||||
ToggleMenu ->
|
||||
( { model | menuOpen = not model.menuOpen }, Cmd.none, NavNone )
|
||||
( { model | menuOpen = not model.menuOpen }, Cmd.none )
|
||||
|
||||
ReloadItem ->
|
||||
if model.item.id == "" then
|
||||
( model, Cmd.none, NavNone )
|
||||
( model, Cmd.none )
|
||||
|
||||
else
|
||||
( model, Api.itemDetail flags model.item.id GetItemResp, NavNone )
|
||||
( model, Api.itemDetail flags model.item.id GetItemResp )
|
||||
|
||||
TagDropdownMsg m ->
|
||||
let
|
||||
@ -394,7 +397,7 @@ update flags msg model =
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
( newModel, Cmd.batch [ save, Cmd.map TagDropdownMsg c2 ], NavNone )
|
||||
( newModel, Cmd.batch [ save, Cmd.map TagDropdownMsg c2 ] )
|
||||
|
||||
DirDropdownMsg m ->
|
||||
let
|
||||
@ -411,7 +414,7 @@ update flags msg model =
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
( newModel, Cmd.batch [ save, Cmd.map DirDropdownMsg c2 ] ) |> noNav
|
||||
( newModel, Cmd.batch [ save, Cmd.map DirDropdownMsg c2 ] )
|
||||
|
||||
OrgDropdownMsg m ->
|
||||
let
|
||||
@ -431,7 +434,7 @@ update flags msg model =
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
( newModel, Cmd.batch [ save, Cmd.map OrgDropdownMsg c2 ] ) |> noNav
|
||||
( newModel, Cmd.batch [ save, Cmd.map OrgDropdownMsg c2 ] )
|
||||
|
||||
CorrPersonMsg m ->
|
||||
let
|
||||
@ -451,7 +454,7 @@ update flags msg model =
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
( newModel, Cmd.batch [ save, Cmd.map CorrPersonMsg c2 ] ) |> noNav
|
||||
( newModel, Cmd.batch [ save, Cmd.map CorrPersonMsg c2 ] )
|
||||
|
||||
ConcPersonMsg m ->
|
||||
let
|
||||
@ -471,7 +474,7 @@ update flags msg model =
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
( newModel, Cmd.batch [ save, Cmd.map ConcPersonMsg c2 ] ) |> noNav
|
||||
( newModel, Cmd.batch [ save, Cmd.map ConcPersonMsg c2 ] )
|
||||
|
||||
ConcEquipMsg m ->
|
||||
let
|
||||
@ -491,13 +494,13 @@ update flags msg model =
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
( newModel, Cmd.batch [ save, Cmd.map ConcEquipMsg c2 ] ) |> noNav
|
||||
( newModel, Cmd.batch [ save, Cmd.map ConcEquipMsg c2 ] )
|
||||
|
||||
SetName str ->
|
||||
( { model | nameModel = str }, Cmd.none ) |> noNav
|
||||
( { model | nameModel = str }, Cmd.none )
|
||||
|
||||
SaveName ->
|
||||
( model, setName flags model ) |> noNav
|
||||
( model, setName flags model )
|
||||
|
||||
SetNotes str ->
|
||||
( { model
|
||||
@ -510,16 +513,20 @@ update flags msg model =
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|> noNav
|
||||
|
||||
ToggleNotes ->
|
||||
( { model | notesHidden = not model.notesHidden }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
SaveNotes ->
|
||||
( model, setNotes flags model ) |> noNav
|
||||
( model, setNotes flags model )
|
||||
|
||||
ConfirmItem ->
|
||||
( model, Api.setConfirmed flags model.item.id SaveResp ) |> noNav
|
||||
( model, Api.setConfirmed flags model.item.id SaveResp )
|
||||
|
||||
UnconfirmItem ->
|
||||
( model, Api.setUnconfirmed flags model.item.id SaveResp ) |> noNav
|
||||
( model, Api.setUnconfirmed flags model.item.id SaveResp )
|
||||
|
||||
ItemDatePickerMsg m ->
|
||||
let
|
||||
@ -532,13 +539,13 @@ update flags msg model =
|
||||
newModel =
|
||||
{ model | itemDatePicker = dp, itemDate = Just (Comp.DatePicker.midOfDay date) }
|
||||
in
|
||||
( newModel, setDate flags newModel newModel.itemDate ) |> noNav
|
||||
( newModel, setDate flags newModel newModel.itemDate )
|
||||
|
||||
_ ->
|
||||
( { model | itemDatePicker = dp }, Cmd.none ) |> noNav
|
||||
( { model | itemDatePicker = dp }, Cmd.none )
|
||||
|
||||
RemoveDate ->
|
||||
( { model | itemDate = Nothing }, setDate flags model Nothing ) |> noNav
|
||||
( { model | itemDate = Nothing }, setDate flags model Nothing )
|
||||
|
||||
DueDatePickerMsg m ->
|
||||
let
|
||||
@ -551,13 +558,13 @@ update flags msg model =
|
||||
newModel =
|
||||
{ model | dueDatePicker = dp, dueDate = Just (Comp.DatePicker.midOfDay date) }
|
||||
in
|
||||
( newModel, setDueDate flags newModel newModel.dueDate ) |> noNav
|
||||
( newModel, setDueDate flags newModel newModel.dueDate )
|
||||
|
||||
_ ->
|
||||
( { model | dueDatePicker = dp }, Cmd.none ) |> noNav
|
||||
( { model | dueDatePicker = dp }, Cmd.none )
|
||||
|
||||
RemoveDueDate ->
|
||||
( { model | dueDate = Nothing }, setDueDate flags model Nothing ) |> noNav
|
||||
( { model | dueDate = Nothing }, setDueDate flags model Nothing )
|
||||
|
||||
YesNoMsg m ->
|
||||
let
|
||||
@ -571,67 +578,67 @@ update flags msg model =
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
( { model | deleteConfirm = cm }, cmd ) |> noNav
|
||||
( { model | deleteConfirm = cm }, cmd )
|
||||
|
||||
RequestDelete ->
|
||||
update flags (YesNoMsg Comp.YesNoDimmer.activate) model
|
||||
update key flags next (YesNoMsg Comp.YesNoDimmer.activate) model
|
||||
|
||||
SetCorrOrgSuggestion idname ->
|
||||
( model, setCorrOrg flags model (Just idname) ) |> noNav
|
||||
( model, setCorrOrg flags model (Just idname) )
|
||||
|
||||
SetCorrPersonSuggestion idname ->
|
||||
( model, setCorrPerson flags model (Just idname) ) |> noNav
|
||||
( model, setCorrPerson flags model (Just idname) )
|
||||
|
||||
SetConcPersonSuggestion idname ->
|
||||
( model, setConcPerson flags model (Just idname) ) |> noNav
|
||||
( model, setConcPerson flags model (Just idname) )
|
||||
|
||||
SetConcEquipSuggestion idname ->
|
||||
( model, setConcEquip flags model (Just idname) ) |> noNav
|
||||
( model, setConcEquip flags model (Just idname) )
|
||||
|
||||
SetItemDateSuggestion date ->
|
||||
( model, setDate flags model (Just date) ) |> noNav
|
||||
( model, setDate flags model (Just date) )
|
||||
|
||||
SetDueDateSuggestion date ->
|
||||
( model, setDueDate flags model (Just date) ) |> noNav
|
||||
( model, setDueDate flags model (Just date) )
|
||||
|
||||
GetTagsResp (Ok tags) ->
|
||||
let
|
||||
tagList =
|
||||
Comp.Dropdown.SetOptions tags.items
|
||||
|
||||
( m1, c1, _ ) =
|
||||
update flags (TagDropdownMsg tagList) model
|
||||
( m1, c1 ) =
|
||||
update key flags next (TagDropdownMsg tagList) model
|
||||
in
|
||||
( m1, c1 ) |> noNav
|
||||
( m1, c1 )
|
||||
|
||||
GetTagsResp (Err _) ->
|
||||
( model, Cmd.none ) |> noNav
|
||||
( model, Cmd.none )
|
||||
|
||||
GetOrgResp (Ok orgs) ->
|
||||
let
|
||||
opts =
|
||||
Comp.Dropdown.SetOptions orgs.items
|
||||
in
|
||||
update flags (OrgDropdownMsg opts) model
|
||||
update key flags next (OrgDropdownMsg opts) model
|
||||
|
||||
GetOrgResp (Err _) ->
|
||||
( model, Cmd.none ) |> noNav
|
||||
( model, Cmd.none )
|
||||
|
||||
GetPersonResp (Ok ps) ->
|
||||
let
|
||||
opts =
|
||||
Comp.Dropdown.SetOptions ps.items
|
||||
|
||||
( m1, c1, _ ) =
|
||||
update flags (CorrPersonMsg opts) model
|
||||
( m1, c1 ) =
|
||||
update key flags next (CorrPersonMsg opts) model
|
||||
|
||||
( m2, c2, _ ) =
|
||||
update flags (ConcPersonMsg opts) m1
|
||||
( m2, c2 ) =
|
||||
update key flags next (ConcPersonMsg opts) m1
|
||||
in
|
||||
( m2, Cmd.batch [ c1, c2 ] ) |> noNav
|
||||
( m2, Cmd.batch [ c1, c2 ] )
|
||||
|
||||
GetPersonResp (Err _) ->
|
||||
( model, Cmd.none ) |> noNav
|
||||
( model, Cmd.none )
|
||||
|
||||
GetEquipResp (Ok equips) ->
|
||||
let
|
||||
@ -641,42 +648,47 @@ update flags msg model =
|
||||
equips.items
|
||||
)
|
||||
in
|
||||
update flags (ConcEquipMsg opts) model
|
||||
update key flags next (ConcEquipMsg opts) model
|
||||
|
||||
GetEquipResp (Err _) ->
|
||||
( model, Cmd.none ) |> noNav
|
||||
( model, Cmd.none )
|
||||
|
||||
SaveResp (Ok res) ->
|
||||
if res.success then
|
||||
( model, Api.itemDetail flags model.item.id GetItemResp ) |> noNav
|
||||
( model, Api.itemDetail flags model.item.id GetItemResp )
|
||||
|
||||
else
|
||||
( model, Cmd.none ) |> noNav
|
||||
( model, Cmd.none )
|
||||
|
||||
SaveResp (Err _) ->
|
||||
( model, Cmd.none ) |> noNav
|
||||
( model, Cmd.none )
|
||||
|
||||
DeleteResp (Ok res) ->
|
||||
if res.success then
|
||||
( model, Cmd.none, NavNextOrBack )
|
||||
case next of
|
||||
Just id ->
|
||||
( model, Page.set key (ItemDetailPage id) )
|
||||
|
||||
Nothing ->
|
||||
( model, Page.set key HomePage )
|
||||
|
||||
else
|
||||
( model, Cmd.none ) |> noNav
|
||||
( model, Cmd.none )
|
||||
|
||||
DeleteResp (Err _) ->
|
||||
( model, Cmd.none ) |> noNav
|
||||
( model, Cmd.none )
|
||||
|
||||
GetItemResp (Ok item) ->
|
||||
update flags (SetItem item) model
|
||||
update key flags next (SetItem item) model
|
||||
|
||||
GetItemResp (Err _) ->
|
||||
( model, Cmd.none ) |> noNav
|
||||
( model, Cmd.none )
|
||||
|
||||
GetProposalResp (Ok ip) ->
|
||||
( { model | itemProposals = ip }, Cmd.none ) |> noNav
|
||||
( { model | itemProposals = ip }, Cmd.none )
|
||||
|
||||
GetProposalResp (Err _) ->
|
||||
( model, Cmd.none ) |> noNav
|
||||
( model, Cmd.none )
|
||||
|
||||
|
||||
|
||||
@ -692,21 +704,38 @@ actionInputDatePicker =
|
||||
{ ds | containerClassList = [ ( "ui action input", True ) ] }
|
||||
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
view : { prev : Maybe String, next : Maybe String } -> Model -> Html Msg
|
||||
view inav model =
|
||||
div []
|
||||
[ div
|
||||
[ renderItemInfo model
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui ablue-comp menu", True )
|
||||
]
|
||||
]
|
||||
[ a [ class "item", href "", onClick (NavClick NavBack) ]
|
||||
[ a [ class "item", Page.href HomePage ]
|
||||
[ i [ class "arrow left icon" ] []
|
||||
]
|
||||
, a [ class "item", href "", onClick (NavClick NavPrev) ]
|
||||
, a
|
||||
[ classList
|
||||
[ ( "item", True )
|
||||
, ( "disabled", inav.prev == Nothing )
|
||||
]
|
||||
, Maybe.map ItemDetailPage inav.prev
|
||||
|> Maybe.map Page.href
|
||||
|> Maybe.withDefault (href "#")
|
||||
]
|
||||
[ i [ class "caret square left outline icon" ] []
|
||||
]
|
||||
, a [ class "item", href "", onClick (NavClick NavNext) ]
|
||||
, a
|
||||
[ classList
|
||||
[ ( "item", True )
|
||||
, ( "disabled", inav.next == Nothing )
|
||||
]
|
||||
, Maybe.map ItemDetailPage inav.next
|
||||
|> Maybe.map Page.href
|
||||
|> Maybe.withDefault (href "#")
|
||||
]
|
||||
[ i [ class "caret square right outline icon" ] []
|
||||
]
|
||||
, a
|
||||
@ -722,9 +751,10 @@ view model =
|
||||
]
|
||||
]
|
||||
, div [ class "ui grid" ]
|
||||
[ div
|
||||
[ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "six wide column", True )
|
||||
[ ( "four wide column", True )
|
||||
, ( "invisible", not model.menuOpen )
|
||||
]
|
||||
]
|
||||
@ -736,17 +766,17 @@ view model =
|
||||
)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ten", model.menuOpen )
|
||||
[ ( "twelve", model.menuOpen )
|
||||
, ( "sixteen", not model.menuOpen )
|
||||
, ( "wide column", True )
|
||||
]
|
||||
]
|
||||
<|
|
||||
List.concat
|
||||
[ [ renderItemInfo model ]
|
||||
, [ renderAttachmentsTabMenu model ]
|
||||
[ renderNotes model
|
||||
, [ renderAttachmentsTabMenu model
|
||||
]
|
||||
, renderAttachmentsTabBody model
|
||||
, renderNotes model
|
||||
, renderIdInfo model
|
||||
]
|
||||
]
|
||||
@ -776,11 +806,31 @@ renderNotes model =
|
||||
[]
|
||||
|
||||
Just str ->
|
||||
[ h3 [ class "ui header" ]
|
||||
[ text "Notes"
|
||||
if model.notesHidden then
|
||||
[ div [ class "ui segment" ]
|
||||
[ a
|
||||
[ class "ui top left attached label"
|
||||
, onClick ToggleNotes
|
||||
, href "#"
|
||||
]
|
||||
[ i [ class "eye icon" ] []
|
||||
, text "Show notes…"
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
else
|
||||
[ div [ class "ui segment" ]
|
||||
[ Markdown.toHtml [ class "item-notes" ] str
|
||||
, a
|
||||
[ class "ui right corner label"
|
||||
, onClick ToggleNotes
|
||||
, href "#"
|
||||
]
|
||||
[ i [ class "delete icon" ] []
|
||||
]
|
||||
]
|
||||
]
|
||||
, Markdown.toHtml [ class "item-notes" ] str
|
||||
]
|
||||
|
||||
|
||||
renderAttachmentsTabMenu : Model -> Html Msg
|
||||
@ -829,12 +879,6 @@ renderAttachmentsTabBody model =
|
||||
renderItemInfo : Model -> Html Msg
|
||||
renderItemInfo model =
|
||||
let
|
||||
name =
|
||||
div [ class "item" ]
|
||||
[ i [ class (Data.Direction.iconFromString model.item.direction) ] []
|
||||
, text model.item.name
|
||||
]
|
||||
|
||||
date =
|
||||
div [ class "item" ]
|
||||
[ Maybe.withDefault model.item.created model.item.itemDate
|
||||
@ -876,7 +920,7 @@ renderItemInfo model =
|
||||
]
|
||||
in
|
||||
div [ class "ui fluid container" ]
|
||||
([ h2 [ class "ui header" ]
|
||||
(h2 [ class "ui header" ]
|
||||
[ i [ class (Data.Direction.iconFromString model.item.direction) ] []
|
||||
, div [ class "content" ]
|
||||
[ text model.item.name
|
||||
@ -905,8 +949,7 @@ renderItemInfo model =
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
++ renderTags model
|
||||
:: renderTags model
|
||||
)
|
||||
|
||||
|
||||
@ -973,8 +1016,7 @@ renderEditButtons model =
|
||||
renderEditForm : Model -> Html Msg
|
||||
renderEditForm model =
|
||||
div [ class "ui attached segment" ]
|
||||
[ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
, div [ class "ui form" ]
|
||||
[ div [ class "ui form" ]
|
||||
[ div [ class "field" ]
|
||||
[ label []
|
||||
[ i [ class "tags icon" ] []
|
||||
@ -986,7 +1028,12 @@ renderEditForm model =
|
||||
[ label [] [ text "Name" ]
|
||||
, div [ class "ui action input" ]
|
||||
[ input [ type_ "text", value model.nameModel, onInput SetName ] []
|
||||
, button [ class "ui icon button", onClick SaveName ] [ i [ class "save outline icon" ] [] ]
|
||||
, button
|
||||
[ class "ui icon button"
|
||||
, onClick SaveName
|
||||
]
|
||||
[ i [ class "save outline icon" ] []
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "field" ]
|
||||
@ -996,7 +1043,12 @@ renderEditForm model =
|
||||
, div [ class " field" ]
|
||||
[ label [] [ text "Date" ]
|
||||
, div [ class "ui action input" ]
|
||||
[ Html.map ItemDatePickerMsg (Comp.DatePicker.viewTime model.itemDate actionInputDatePicker model.itemDatePicker)
|
||||
[ Html.map ItemDatePickerMsg
|
||||
(Comp.DatePicker.viewTime
|
||||
model.itemDate
|
||||
actionInputDatePicker
|
||||
model.itemDatePicker
|
||||
)
|
||||
, a [ class "ui icon button", href "", onClick RemoveDate ]
|
||||
[ i [ class "trash alternate outline icon" ] []
|
||||
]
|
||||
@ -1006,7 +1058,12 @@ renderEditForm model =
|
||||
, div [ class " field" ]
|
||||
[ label [] [ text "Due Date" ]
|
||||
, div [ class "ui action input" ]
|
||||
[ Html.map DueDatePickerMsg (Comp.DatePicker.viewTime model.dueDate actionInputDatePicker model.dueDatePicker)
|
||||
[ Html.map DueDatePickerMsg
|
||||
(Comp.DatePicker.viewTime
|
||||
model.dueDate
|
||||
actionInputDatePicker
|
||||
model.dueDatePicker
|
||||
)
|
||||
, a [ class "ui icon button", href "", onClick RemoveDueDate ]
|
||||
[ i [ class "trash alternate outline icon" ] [] ]
|
||||
]
|
||||
|
@ -10,6 +10,7 @@ module Page exposing
|
||||
, pageFromString
|
||||
, pageName
|
||||
, pageToString
|
||||
, set
|
||||
, uploadId
|
||||
)
|
||||
|
||||
@ -31,6 +32,7 @@ type Page
|
||||
| RegisterPage
|
||||
| UploadPage (Maybe String)
|
||||
| NewInvitePage
|
||||
| ItemDetailPage String
|
||||
|
||||
|
||||
isSecured : Page -> Bool
|
||||
@ -63,6 +65,9 @@ isSecured page =
|
||||
UploadPage arg ->
|
||||
Util.Maybe.isEmpty arg
|
||||
|
||||
ItemDetailPage _ ->
|
||||
True
|
||||
|
||||
|
||||
isOpen : Page -> Bool
|
||||
isOpen page =
|
||||
@ -114,6 +119,9 @@ pageName page =
|
||||
Nothing ->
|
||||
"Upload"
|
||||
|
||||
ItemDetailPage _ ->
|
||||
"Item"
|
||||
|
||||
|
||||
loginPageReferrer : Page -> Maybe Page
|
||||
loginPageReferrer page =
|
||||
@ -169,6 +177,9 @@ pageToString page =
|
||||
NewInvitePage ->
|
||||
"/app/newinvite"
|
||||
|
||||
ItemDetailPage id ->
|
||||
"/app/item/" ++ id
|
||||
|
||||
|
||||
pageFromString : String -> Maybe Page
|
||||
pageFromString str =
|
||||
@ -191,6 +202,11 @@ href page =
|
||||
Attr.href (pageToString page)
|
||||
|
||||
|
||||
set : Nav.Key -> Page -> Cmd msg
|
||||
set key page =
|
||||
Nav.pushUrl key (pageToString page)
|
||||
|
||||
|
||||
goto : Page -> Cmd msg
|
||||
goto page =
|
||||
Nav.load (pageToString page)
|
||||
@ -215,6 +231,7 @@ parser =
|
||||
, Parser.map (\s -> UploadPage (Just s)) (s pathPrefix </> s "upload" </> string)
|
||||
, Parser.map (UploadPage Nothing) (s pathPrefix </> s "upload")
|
||||
, Parser.map NewInvitePage (s pathPrefix </> s "newinvite")
|
||||
, Parser.map ItemDetailPage (s pathPrefix </> s "item" </> string)
|
||||
]
|
||||
|
||||
|
||||
|
@ -3,11 +3,11 @@ module Page.Home.Data exposing
|
||||
, Msg(..)
|
||||
, ViewMode(..)
|
||||
, emptyModel
|
||||
, itemNav
|
||||
)
|
||||
|
||||
import Api.Model.ItemDetail exposing (ItemDetail)
|
||||
import Api.Model.ItemLightList exposing (ItemLightList)
|
||||
import Comp.ItemDetail
|
||||
import Comp.ItemList
|
||||
import Comp.SearchMenu
|
||||
import Http
|
||||
@ -17,7 +17,6 @@ type alias Model =
|
||||
{ searchMenuModel : Comp.SearchMenu.Model
|
||||
, itemListModel : Comp.ItemList.Model
|
||||
, searchInProgress : Bool
|
||||
, itemDetailModel : Comp.ItemDetail.Model
|
||||
, viewMode : ViewMode
|
||||
}
|
||||
|
||||
@ -26,7 +25,6 @@ emptyModel : Model
|
||||
emptyModel =
|
||||
{ searchMenuModel = Comp.SearchMenu.emptyModel
|
||||
, itemListModel = Comp.ItemList.emptyModel
|
||||
, itemDetailModel = Comp.ItemDetail.emptyModel
|
||||
, searchInProgress = False
|
||||
, viewMode = Listing
|
||||
}
|
||||
@ -38,10 +36,22 @@ type Msg
|
||||
| ItemListMsg Comp.ItemList.Msg
|
||||
| ItemSearchResp (Result Http.Error ItemLightList)
|
||||
| DoSearch
|
||||
| ItemDetailMsg Comp.ItemDetail.Msg
|
||||
| ItemDetailResp (Result Http.Error ItemDetail)
|
||||
|
||||
|
||||
type ViewMode
|
||||
= Listing
|
||||
| Detail
|
||||
|
||||
|
||||
itemNav : String -> Model -> { prev : Maybe String, next : Maybe String }
|
||||
itemNav id model =
|
||||
let
|
||||
prev =
|
||||
Comp.ItemList.prevItem model.itemListModel id
|
||||
|
||||
next =
|
||||
Comp.ItemList.nextItem model.itemListModel id
|
||||
in
|
||||
{ prev = Maybe.map .id prev
|
||||
, next = Maybe.map .id next
|
||||
}
|
||||
|
@ -1,21 +1,22 @@
|
||||
module Page.Home.Update exposing (update)
|
||||
|
||||
import Api
|
||||
import Browser.Navigation as Nav
|
||||
import Comp.ItemDetail
|
||||
import Comp.ItemList
|
||||
import Comp.SearchMenu
|
||||
import Data.Flags exposing (Flags)
|
||||
import Page exposing (Page(..))
|
||||
import Page.Home.Data exposing (..)
|
||||
import Util.Update
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
update : Nav.Key -> Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update key flags msg model =
|
||||
case msg of
|
||||
Init ->
|
||||
Util.Update.andThen1
|
||||
[ update flags (SearchMenuMsg Comp.SearchMenu.Init)
|
||||
, update flags (ItemDetailMsg Comp.ItemDetail.Init)
|
||||
[ update key flags (SearchMenuMsg Comp.SearchMenu.Init)
|
||||
, doSearch flags
|
||||
]
|
||||
model
|
||||
@ -45,7 +46,7 @@ update flags msg model =
|
||||
cmd =
|
||||
case mitem of
|
||||
Just item ->
|
||||
Api.itemDetail flags item.id ItemDetailResp
|
||||
Page.set key (ItemDetailPage item.id)
|
||||
|
||||
Nothing ->
|
||||
Cmd.none
|
||||
@ -57,7 +58,7 @@ update flags msg model =
|
||||
m =
|
||||
{ model | searchInProgress = False, viewMode = Listing }
|
||||
in
|
||||
update flags (ItemListMsg (Comp.ItemList.SetResults list)) m
|
||||
update key flags (ItemListMsg (Comp.ItemList.SetResults list)) m
|
||||
|
||||
ItemSearchResp (Err _) ->
|
||||
( { model | searchInProgress = False }, Cmd.none )
|
||||
@ -65,58 +66,6 @@ update flags msg model =
|
||||
DoSearch ->
|
||||
doSearch flags model
|
||||
|
||||
ItemDetailMsg m ->
|
||||
let
|
||||
( m2, c2, nav ) =
|
||||
Comp.ItemDetail.update flags m model.itemDetailModel
|
||||
|
||||
newModel =
|
||||
{ model | itemDetailModel = m2 }
|
||||
|
||||
newCmd =
|
||||
Cmd.map ItemDetailMsg c2
|
||||
in
|
||||
case nav of
|
||||
Comp.ItemDetail.NavBack ->
|
||||
doSearch flags newModel
|
||||
|
||||
Comp.ItemDetail.NavPrev ->
|
||||
case Comp.ItemList.prevItem model.itemListModel m2.item.id of
|
||||
Just n ->
|
||||
( newModel, Cmd.batch [ newCmd, Api.itemDetail flags n.id ItemDetailResp ] )
|
||||
|
||||
Nothing ->
|
||||
( newModel, newCmd )
|
||||
|
||||
Comp.ItemDetail.NavNext ->
|
||||
case Comp.ItemList.nextItem model.itemListModel m2.item.id of
|
||||
Just n ->
|
||||
( newModel, Cmd.batch [ newCmd, Api.itemDetail flags n.id ItemDetailResp ] )
|
||||
|
||||
Nothing ->
|
||||
( newModel, newCmd )
|
||||
|
||||
Comp.ItemDetail.NavNextOrBack ->
|
||||
case Comp.ItemList.nextItem model.itemListModel m2.item.id of
|
||||
Just n ->
|
||||
( newModel, Cmd.batch [ newCmd, Api.itemDetail flags n.id ItemDetailResp ] )
|
||||
|
||||
Nothing ->
|
||||
doSearch flags newModel
|
||||
|
||||
Comp.ItemDetail.NavNone ->
|
||||
( newModel, newCmd )
|
||||
|
||||
ItemDetailResp (Ok item) ->
|
||||
let
|
||||
m =
|
||||
{ model | viewMode = Detail }
|
||||
in
|
||||
update flags (ItemDetailMsg (Comp.ItemDetail.SetItem item)) m
|
||||
|
||||
ItemDetailResp (Err _) ->
|
||||
( model, Cmd.none )
|
||||
|
||||
|
||||
doSearch : Flags -> Model -> ( Model, Cmd Msg )
|
||||
doSearch flags model =
|
||||
|
@ -42,7 +42,7 @@ view model =
|
||||
Html.map ItemListMsg (Comp.ItemList.view model.itemListModel)
|
||||
|
||||
Detail ->
|
||||
Html.map ItemDetailMsg (Comp.ItemDetail.view model.itemDetailModel)
|
||||
div [] []
|
||||
]
|
||||
]
|
||||
|
||||
|
22
modules/webapp/src/main/elm/Page/ItemDetail/Data.elm
Normal file
22
modules/webapp/src/main/elm/Page/ItemDetail/Data.elm
Normal file
@ -0,0 +1,22 @@
|
||||
module Page.ItemDetail.Data exposing (Model, Msg(..), emptyModel)
|
||||
|
||||
import Api.Model.ItemDetail exposing (ItemDetail)
|
||||
import Comp.ItemDetail
|
||||
import Http
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ detail : Comp.ItemDetail.Model
|
||||
}
|
||||
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ detail = Comp.ItemDetail.emptyModel
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= Init String
|
||||
| ItemDetailMsg Comp.ItemDetail.Msg
|
||||
| ItemResp (Result Http.Error ItemDetail)
|
39
modules/webapp/src/main/elm/Page/ItemDetail/Update.elm
Normal file
39
modules/webapp/src/main/elm/Page/ItemDetail/Update.elm
Normal file
@ -0,0 +1,39 @@
|
||||
module Page.ItemDetail.Update exposing (update)
|
||||
|
||||
import Api
|
||||
import Browser.Navigation as Nav
|
||||
import Comp.ItemDetail
|
||||
import Data.Flags exposing (Flags)
|
||||
import Page.ItemDetail.Data exposing (Model, Msg(..))
|
||||
|
||||
|
||||
update : Nav.Key -> Flags -> Maybe String -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update key flags next msg model =
|
||||
case msg of
|
||||
Init id ->
|
||||
let
|
||||
( lm, lc ) =
|
||||
Comp.ItemDetail.update key flags next Comp.ItemDetail.Init model.detail
|
||||
in
|
||||
( { model | detail = lm }
|
||||
, Cmd.batch [ Api.itemDetail flags id ItemResp, Cmd.map ItemDetailMsg lc ]
|
||||
)
|
||||
|
||||
ItemDetailMsg lmsg ->
|
||||
let
|
||||
( lm, lc ) =
|
||||
Comp.ItemDetail.update key flags next lmsg model.detail
|
||||
in
|
||||
( { model | detail = lm }
|
||||
, Cmd.map ItemDetailMsg lc
|
||||
)
|
||||
|
||||
ItemResp (Ok item) ->
|
||||
let
|
||||
lmsg =
|
||||
Comp.ItemDetail.SetItem item
|
||||
in
|
||||
update key flags next (ItemDetailMsg lmsg) model
|
||||
|
||||
ItemResp (Err err) ->
|
||||
( model, Cmd.none )
|
19
modules/webapp/src/main/elm/Page/ItemDetail/View.elm
Normal file
19
modules/webapp/src/main/elm/Page/ItemDetail/View.elm
Normal file
@ -0,0 +1,19 @@
|
||||
module Page.ItemDetail.View exposing (view)
|
||||
|
||||
import Comp.ItemDetail
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Page.ItemDetail.Data exposing (Model, Msg(..))
|
||||
|
||||
|
||||
type alias ItemNav =
|
||||
{ prev : Maybe String
|
||||
, next : Maybe String
|
||||
}
|
||||
|
||||
|
||||
view : ItemNav -> Model -> Html Msg
|
||||
view inav model =
|
||||
div [ class "ui fluid container item-detail-page" ]
|
||||
[ Html.map ItemDetailMsg (Comp.ItemDetail.view inav model.detail)
|
||||
]
|
@ -59,6 +59,12 @@
|
||||
background: aliceblue;
|
||||
}
|
||||
|
||||
.default-layout .ui.fluid.container.item-detail-page {
|
||||
padding-top: 1em;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.ui.search.dropdown.open {
|
||||
z-index: 20;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user