Persist project across pages.

[?]
Jan 25, 2021, 12:47 AM
B4MTB6UOH5VPZQ7KDQ23TZSR3CIFGVGVBEFL26LMFAQ5RL7CXPRQC

Dependencies

  • [2] QAC2QJ32 Add project overview page to client.
  • [3] 2J37EVJM Check for an open interval on project switch.
  • [4] SAESJLLY Initial experiments in hash routing.
  • [5] IR75ZMX3 Return actual events for interval ends, not just timestamps.
  • [6] OUR4PAOT Use local dates for display of intervals.
  • [7] WRPIYG3E Use project listing functionality to check for whether we have a cookie.
  • [8] JXG3FCXY Upgrade ps + halogen versions.
  • [9] J6S23MDG Use server timestamps for interval start and end.
  • [10] NJNMO72S Add zcash.com submodule and update client to modern halogen.
  • [11] ZIG57EE6 Fix project selection, end log end on project switch.
  • [12] QU5FW67R Add project selection to time tracker.
  • [13] QMEYU4MW Add display for prior intervals.
  • [14] RSF6UAJK Break out api module for timeline.
  • [15] PT4276XC Add logout functionality.
  • [16] BFZN4SUA Make timeline component work.
  • [*] RB2ETNIF Add skeletal PureScript client project.

Change contents

  • replacement in client/src/Aftok/Overview.purs at line 18
    [2.679][2.679:706]()
    import Data.Foldable (any)
    [2.679]
    [2.706]
    import Data.Foldable (all)
  • replacement in client/src/Aftok/Overview.purs at line 126
    [2.3651][2.3651:3767]()
    [HH.slot _projectList unit (Project.projectListComponent system pcaps) unit (Just <<< ProjectSelected)]
    [2.3651]
    [2.3767]
    [HH.slot _projectList unit (Project.projectListComponent system pcaps) st.selectedProject (Just <<< ProjectSelected)]
  • replacement in client/src/Aftok/Overview.purs at line 145
    [2.4247][2.4247:4343]()
    when (any (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject) $ do
    [2.4247]
    [2.4343]
    when (all (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject) $ do
  • replacement in client/src/Aftok/Project.purs at line 14
    [3.33][3.996:1026](),[2.4659][3.996:1026](),[3.996][3.996:1026]()
    import Data.Maybe (Maybe(..))
    [2.4659]
    [3.108]
    import Data.Foldable (any)
    import Data.Maybe (Maybe(..), isNothing)
  • edit in client/src/Aftok/Project.purs at line 40
    [3.1524]
    [3.527]
    type ProjectInput = Maybe Project
  • replacement in client/src/Aftok/Project.purs at line 43
    [3.548][3.548:578]()
    { projects :: Array Project
    [3.548]
    [3.578]
    { selectedProject :: Maybe Project
    , projects :: Array Project
  • replacement in client/src/Aftok/Project.purs at line 62
    [3.458][3.787:834](),[3.787][3.787:834]()
    -> H.Component HH.HTML query input Project m
    [3.458]
    [3.459]
    -> H.Component HH.HTML query ProjectInput Project m
  • replacement in client/src/Aftok/Project.purs at line 72
    [3.1025][3.1025:1106]()
    initialState :: input -> ProjectCState
    initialState _ = { projects: [] }
    [3.1025]
    [3.1106]
    initialState :: ProjectInput -> ProjectCState
    initialState input = { selectedProject: input, projects: [] }
  • replacement in client/src/Aftok/Project.purs at line 77
    [3.1207][3.1207:1320](),[3.1320][3.314:867]()
    let renderOption (Project' p) =
    HH.option [P.value $ pidStr p.projectId] [HH.text p.projectName]
    in HH.div
    [P.classes (ClassName <$> ["form-group"])]
    [HH.label
    [ P.classes (ClassName <$> ["sr-only"])
    , P.for "projectSelect"
    ]
    [ HH.text "Project" ]
    ,HH.select
    [P.classes (ClassName <$> ["form-control"])
    ,P.id_ "projectSelect"
    ,E.onSelectedIndexChange (Just <<< Select)
    ]
    ([HH.option [P.selected true, P.disabled true] [HH.text "Select a project"]] <> map renderOption st.projects)
    ]
    [3.1207]
    [3.1518]
    HH.div
    [P.classes (ClassName <$> ["form-group"])]
    [ HH.label
    [ P.classes (ClassName <$> ["sr-only"])
    , P.for "projectSelect"
    ]
    [ HH.text "Project" ]
    , HH.select
    [P.classes (ClassName <$> ["form-control"])
    ,P.id_ "projectSelect"
    ,E.onSelectedIndexChange (Just <<< Select)
    ]
    ( [HH.option [P.selected (isNothing st.selectedProject), P.disabled true] [HH.text "Select a project"]]
    <> map renderOption st.projects
    )
    ]
    where
    renderOption (Project' p) =
    HH.option
    [ P.selected (any (\(Project' p') -> p'.projectId == p.projectId) st.selectedProject)
    , P.value $ pidStr p.projectId
    ]
    [HH.text p.projectName]
  • edit in client/src/Aftok/Timeline.purs at line 95
    [3.1119]
    [3.1119]
    type TimelineInput = Maybe Project
  • replacement in client/src/Aftok/Timeline.purs at line 129
    [3.1170][2.4966:4992]()
    :: forall query input m
    [3.1170]
    [3.4330]
    :: forall query m
  • replacement in client/src/Aftok/Timeline.purs at line 134
    [3.4401][2.4993:5045]()
    -> H.Component HH.HTML query input ProjectEvent m
    [3.4401]
    [3.4447]
    -> H.Component HH.HTML query TimelineInput ProjectEvent m
  • replacement in client/src/Aftok/Timeline.purs at line 143
    [3.4429][3.302418:302461](),[3.302461][3.1315:1336](),[3.1336][3.1244:1277]()
    initialState :: input -> TimelineState
    initialState _ =
    { selectedProject: Nothing
    [3.4429]
    [3.4560]
    initialState :: TimelineInput -> TimelineState
    initialState input =
    { selectedProject: input
  • replacement in client/src/Aftok/Timeline.purs at line 164
    [3.1834][3.4704:4820]()
    [HH.slot _projectList unit (Project.projectListComponent system pcaps) unit (Just <<< ProjectSelected)]
    [3.1834]
    [3.1955]
    [HH.slot _projectList unit (Project.projectListComponent system pcaps) st.selectedProject (Just <<< ProjectSelected)]
  • edit in client/src/Aftok/Timeline.purs at line 191
    [3.1538]
    [3.5214]
    currentProject <- H.gets (_.selectedProject)
    traverse_ setStateForProject currentProject
  • edit in client/src/Aftok/Timeline.purs at line 200
    [2.5252][2.5252:5291]()
    H.raise (ProjectChange p)
  • replacement in client/src/Aftok/Timeline.purs at line 202
    [3.916][3.1825:2085](),[3.1825][3.1825:2085](),[3.2085][3.917:1001](),[3.1001][3.2156:2215](),[3.2156][3.2156:2215](),[3.2215][3.6869:6922]()
    timeSpan <- TL.Before <$> lift system.nowDateTime -- FIXME, should come from a form control
    intervals' <- lift $ caps.listIntervals (unwrap p).projectId timeSpan
    intervals <- lift $ case intervals' of
    Left err ->
    (system.log $ "Error occurred listing intervals" <> show err ) *>
    pure []
    Right ivals ->
    pure $ map (map LoggedEvent) ivals
    [3.916]
    [3.1138]
    H.raise (ProjectChange p)
    setStateForProject p
  • edit in client/src/Aftok/Timeline.purs at line 205
    [3.1139][3.2377:2601](),[3.2377][3.2377:2601](),[3.2601][3.1140:1499](),[3.1499][3.6923:7078](),[3.7078][3.1619:1761](),[3.1619][3.1619:1761](),[3.1761][3.7079:7172](),[3.7172][3.1822:1963](),[3.1822][3.1822:1963](),[3.802][3.5264:5265](),[3.1963][3.5264:5265](),[3.2670][3.5264:5265](),[3.5920][3.5264:5265](),[3.5264][3.5264:5265](),[3.5265][3.1964:2051]()
    history' <- lift <<< runMaybeT $ toHistory system intervals
    hist <- case history' of
    Nothing -> lift $ system.log "Project history was empty." *> pure M.empty
    Just h -> pure h
    latestEventResponse <- lift $ caps.getLatestEvent (unwrap p).projectId
    now <- lift $ system.now
    active <- lift $ case latestEventResponse of
    Left err ->
    (system.log $ "Error occurred retrieving the latest event: " <> show err) *>
    pure Nothing
    Right latestEvent -> do
    let activeInterval :: TL.KeyedEvent Instant -> m (Maybe (Interval TimelineEvent))
    activeInterval ev = case event ev of
    TL.StartEvent i ->
    (system.log $ "Project has an open active interval starting " <> show i) *>
    (Just <<< interval (LoggedEvent ev) <<< PhantomEvent <$> system.now)
    TL.StopEvent _ ->
    pure Nothing
    join <$> traverse activeInterval latestEvent
    H.modify_ (_ { selectedProject = Just p, history = hist, active = active })
  • edit in client/src/Aftok/Timeline.purs at line 238
    [3.3429]
    [3.6288]
    setStateForProject :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit
    setStateForProject p = do
    timeSpan <- TL.Before <$> lift system.nowDateTime -- FIXME, should come from a form control
    intervals' <- lift $ caps.listIntervals (unwrap p).projectId timeSpan
    intervals <- lift $ case intervals' of
    Left err ->
    (system.log $ "Error occurred listing intervals" <> show err ) *>
    pure []
    Right ivals ->
    pure $ map (map LoggedEvent) ivals
    history' <- lift <<< runMaybeT $ toHistory system intervals
    hist <- case history' of
    Nothing -> lift $ system.log "Project history was empty." *> pure M.empty
    Just h -> pure h
  • edit in client/src/Aftok/Timeline.purs at line 255
    [3.6289]
    [3.3430]
    latestEventResponse <- lift $ caps.getLatestEvent (unwrap p).projectId
    now <- lift $ system.now
    active <- lift $ case latestEventResponse of
    Left err ->
    (system.log $ "Error occurred retrieving the latest event: " <> show err) *>
    pure Nothing
    Right latestEvent -> do
    let activeInterval :: TL.KeyedEvent Instant -> m (Maybe (Interval TimelineEvent))
    activeInterval ev = case event ev of
    TL.StartEvent i ->
    (system.log $ "Project has an open active interval starting " <> show i) *>
    (Just <<< interval (LoggedEvent ev) <<< PhantomEvent <$> system.now)
    TL.StopEvent _ ->
    pure Nothing
    join <$> traverse activeInterval latestEvent
    H.modify_ (_ { selectedProject = Just p, history = hist, active = active })
  • replacement in client/src/Main.purs at line 147
    [2.7391][2.7391:7408]()
    HH.div_
    [2.7391]
    [2.7408]
    withNavBar $ HH.div_
  • replacement in client/src/Main.purs at line 152
    [3.1844][2.7530:7636]()
    [ HH.slot _timeline unit (Timeline.component system tlCap pCap) unit (Just <<< ProjectAction) ]
    [3.1844]
    [3.308924]
    [ HH.slot _timeline unit (Timeline.component system tlCap pCap) st.selectedProject (Just <<< ProjectAction) ]