Add project overview page to client.
[?]
Jan 24, 2021, 6:25 PM
QAC2QJ32ZLAK25KJ7SWT27WOZKD2MMDE7OZPHIRRFP2W2QZW7PBACDependencies
- [2]
AAALU5A2Fix client routing - [3]
WRPIYG3EUse project listing functionality to check for whether we have a cookie. - [4]
NJNMO72SAdd zcash.com submodule and update client to modern halogen. - [5]
JXG3FCXYUpgrade ps + halogen versions. - [6]
BFZN4SUAMake timeline component work. - [7]
TUA4HMUDUse real API capability for login. - [8]
QU5FW67RAdd project selection to time tracker. - [9]
EA5BFM5GSplit Login component into its own module. - [10]
ARX7SHY5Begin work on login UI. - [11]
ZIG57EE6Fix project selection, end log end on project switch. - [12]
2J37EVJMCheck for an open interval on project switch. - [13]
J6S23MDGUse server timestamps for interval start and end. - [14]
OUR4PAOTUse local dates for display of intervals. - [15]
HO2PFRABClient login now handles response correctly. - [16]
QMEYU4MWAdd display for prior intervals. - [17]
RSF6UAJKBreak out api module for timeline. - [18]
TKGBRIQTLogin component now raises LoginComplete message. - [19]
SAESJLLYInitial experiments in hash routing. - [20]
IR75ZMX3Return actual events for interval ends, not just timestamps. - [21]
PT4276XCAdd logout functionality. - [*]
RB2ETNIFAdd skeletal PureScript client project. - [*]
O2BZOX7MAdd signup form, captcha check.
Change contents
- replacement in client/src/Aftok/Api/Timeline.purs at line 34
import Aftok.Project (ProjectId(..), pidStr)-- import Aftok.Types (APIError, JsonCompose, decompose, parseDatedResponse)import Aftok.Types (APIError, decompose, parseDatedResponse)import Aftok.Types (APIError, decompose, parseDatedResponse, ProjectId(..), pidStr) - file addition: Overview.purs[3.1]
module Aftok.Overview whereimport Prelude-- import Control.Alt ((<|>))-- import Control.Monad.Rec.Class (forever)-- import Control.Monad.State (State, put, get, evalState)-- import Control.Monad.Trans.Class (lift)-- import Control.Monad.Maybe.Trans (MaybeT(..), runMaybeT)---- import Data.Array (reverse, cons)-- import Data.Date (Date, year, month, day)-- import Data.DateTime as DT-- import Data.DateTime (DateTime(..), date)-- import Data.DateTime.Instant (Instant, unInstant, fromDateTime, toDateTime)-- import Data.Either (Either(..))-- import Data.Enum (fromEnum)import Data.Foldable (any)-- import Data.Map as Mimport Data.Maybe (Maybe(..), isNothing)import Data.Newtype (unwrap)import Data.Symbol (SProxy(..))-- import Data.Time.Duration (Milliseconds(..), Hours(..), Days(..))-- import Data.Traversable (traverse_, traverse)-- import Data.Tuple (Tuple(..))-- import Data.Unfoldable as U-- -- import Text.Format as F -- (format, zeroFill, width)-- import Effect.Aff as Affimport Effect.Aff (Aff)-- import Effect.Class (liftEffect)-- import Effect.Exception (error)-- import Effect.Now (now)import Halogen as H-- import Halogen.Query.EventSource (EventSource)-- import Halogen.Query.EventSource as EventSourceimport Halogen.HTML.Core (ClassName(..))import Halogen.HTML as HH-- import Halogen.HTML.CSS as CSS-- import Halogen.HTML.Events as Eimport Halogen.HTML.Properties as P-- import CSS (backgroundColor, clear, clearBoth, border, rgb, solid, borderRadius, marginLeft)-- import CSS.Display (display, flex)-- import CSS.Geometry (width, height)-- import CSS.Size (px, pct)-- import Aftok.Api.Overview as TL-- import Aftok.Api.Overview-- ( OverviewError,-- Event(..),-- Interval(..),-- TimeInterval,-- KeyedEvent,-- TimeSpan,-- start, end, interval,-- event, eventTime, keyedEvent-- )import Aftok.Project as Project-- import Aftok.Project (Project, Project'(..), ProjectId) --, pidStr)import Aftok.Types (System, Project, ProjectEvent(..))type OverviewInput = Maybe Projecttype OverviewState ={ selectedProject :: Maybe Project}data Invitation= InviteByEmail String| InviteByZaddr Stringdata OverviewAction= Initialize| ProjectSelected Project| Invite Invitationtype Slot id = forall query. H.Slot query ProjectEvent idtype Slots =( projectList :: Project.ProjectListSlot Unit)_projectList = SProxy :: SProxy "projectList"type Capability (m :: Type -> Type) ={}component:: forall query m. Monad m=> System m-> Capability m-> Project.Capability m-> H.Component HH.HTML query OverviewInput ProjectEvent mcomponent system caps pcaps = H.mkComponent{ initialState, render, eval: H.mkEval $ H.defaultEval{ handleAction = eval, initialize = Just Initialize}} whereinitialState :: OverviewInput -> OverviewStateinitialState input ={ selectedProject: input}render :: OverviewState -> H.ComponentHTML OverviewAction Slots mrender st =HH.section[P.classes (ClassName <$> ["section-border", "border-primary"])][HH.div[P.classes (ClassName <$> ["container", "pt-6"])][HH.h1[P.classes (ClassName <$> ["mb-0", "font-weight-bold", "text-center"])][HH.text "Project Overview"],HH.p[P.classes (ClassName <$> ["col-md-5", "text-muted", "text-center", "mx-auto"])][HH.text "Your project timeline"],HH.div_[HH.slot _projectList unit (Project.projectListComponent system pcaps) unit (Just <<< ProjectSelected)],HH.div[P.classes (ClassName <$> if isNothing st.selectedProject then ["collapse"] else [])][]]]eval :: OverviewAction -> H.HalogenM OverviewState OverviewAction Slots ProjectEvent m Uniteval action = docase action ofInitialize -> dopure unitInvite _ -> dopure unitProjectSelected p -> docurrentProject <- H.gets (_.selectedProject)when (any (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject) $ doH.raise (ProjectChange p)H.modify_ (_ { selectedProject = Just p })apiCapability :: Capability AffapiCapability = { }mockCapability :: Capability AffmockCapability = { } - replacement in client/src/Aftok/Project.purs at line 11
import Data.Argonaut.Decode (class DecodeJson, decodeJson, (.:))import Data.Argonaut.Decode (decodeJson) - replacement in client/src/Aftok/Project.purs at line 13
import Data.DateTime (DateTime)import Data.Either (Either(..), note)import Data.Either (Either(..)) - edit in client/src/Aftok/Project.purs at line 15
import Data.Newtype (class Newtype) - edit in client/src/Aftok/Project.purs at line 16
import Data.UUID (UUID, parseUUID, toString) - replacement in client/src/Aftok/Project.purs at line 24
import Aftok.Types (APIError(..), System, parseDate)import Aftok.Types( APIError(..), System, parseDate, pidStr, Project'(..), Project) - edit in client/src/Aftok/Project.purs at line 38[3.331]→[3.331:332](∅→∅),[3.369]→[3.369:404](∅→∅),[3.404]→[3.155:199](∅→∅),[3.199]→[3.314:370](∅→∅),[3.255]→[3.404:435](∅→∅),[3.370]→[3.404:435](∅→∅),[3.404]→[3.404:435](∅→∅),[3.435]→[3.371:411](∅→∅)
newtype ProjectId = ProjectId UUIDderive instance projectIdEq :: Eq ProjectIdderive instance projectIdNewtype :: Newtype ProjectId _pidStr :: ProjectId -> StringpidStr (ProjectId uuid) = toString uuid - edit in client/src/Aftok/Project.purs at line 39[3.1524]→[3.1524:1557](∅→∅),[3.1557]→[3.472:525](∅→∅),[3.525]→[3.1583:1635](∅→∅),[3.1583]→[3.1583:1635](∅→∅),[3.1635]→[3.256:313](∅→∅),[3.313]→[3.1635:1669](∅→∅),[3.1635]→[3.1635:1669](∅→∅),[3.1669]→[3.526:527](∅→∅)
newtype Project' date = Project'{ projectId :: ProjectId, projectName :: String, inceptionDate :: date, initiator :: UUID}derive instance newtypeProject :: Newtype (Project' a) _type Project = Project' DateTime - edit in client/src/Aftok/Project.purs at line 104[3.1870]→[3.1870:1983](∅→∅),[3.1983]→[3.1948:2114](∅→∅),[3.2114]→[3.2246:2247](∅→∅),[3.2246]→[3.2246:2247](∅→∅),[3.2247]→[3.2115:2411](∅→∅),[3.2411]→[3.2247:2248](∅→∅),[3.2247]→[3.2247:2248](∅→∅)
instance decodeJsonProject :: DecodeJson (Project' String) wheredecodeJson json = dox <- decodeJson jsonproject <- x .: "project"projectIdStr <- x .: "projectId"projectId <- ProjectId <$> (note "Failed to decode project UUID" $ parseUUID projectIdStr)projectName <- project .: "projectName"inceptionDate <- project .: "inceptionDate"initiatorStr <- project .: "initiator"initiator <- note "Failed to decode initiator UUID" $ parseUUID initiatorStrpure $ Project' { projectId, projectName, inceptionDate, initiator } - replacement in client/src/Aftok/Timeline.purs at line 62[3.2907]→[3.536:604](∅→∅),[3.604]→[3.6844:6872](∅→∅),[3.989]→[3.6844:6872](∅→∅),[3.6844]→[3.6844:6872](∅→∅)
import Aftok.Project (Project, Project'(..), ProjectId) --, pidStr)import Aftok.Types (System)import Aftok.Types( System,ProjectEvent(..),Project,Project'(..),ProjectId) - replacement in client/src/Aftok/Timeline.purs at line 105
| ProjectSelected Project.Project| ProjectSelected Project - replacement in client/src/Aftok/Timeline.purs at line 110
type Slot id = forall query. H.Slot query Void idtype Slot id = forall query. H.Slot query ProjectEvent id - replacement in client/src/Aftok/Timeline.purs at line 127
:: forall query input output m:: forall query input m - replacement in client/src/Aftok/Timeline.purs at line 132
-> H.Component HH.HTML query input output m-> H.Component HH.HTML query input ProjectEvent m - replacement in client/src/Aftok/Timeline.purs at line 184
eval :: TimelineAction -> H.HalogenM TimelineState TimelineAction Slots output m Uniteval :: TimelineAction -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit - replacement in client/src/Aftok/Timeline.purs at line 195
when (oldActive && any (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject)(traverse_ logEnd currentProject)when (oldActive && any (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject) $ doH.raise (ProjectChange p)(traverse_ logEnd currentProject) - replacement in client/src/Aftok/Timeline.purs at line 248
logStart :: Project -> H.HalogenM TimelineState TimelineAction Slots output m UnitlogStart :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit - replacement in client/src/Aftok/Timeline.purs at line 255
logEnd :: Project -> H.HalogenM TimelineState TimelineAction Slots output m UnitlogEnd :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit - replacement in client/src/Aftok/Types.purs at line 10
import Data.Argonaut.Decode (class DecodeJson, decodeJson)import Data.Argonaut.Decode (class DecodeJson, decodeJson, (.:)) - edit in client/src/Aftok/Types.purs at line 22
import Data.UUID (UUID, toString, parseUUID) - edit in client/src/Aftok/Types.purs at line 104
newtype ProjectId = ProjectId UUIDderive instance projectIdEq :: Eq ProjectIdderive instance projectIdNewtype :: Newtype ProjectId _ - edit in client/src/Aftok/Types.purs at line 109
pidStr :: ProjectId -> StringpidStr (ProjectId uuid) = toString uuidnewtype Project' date = Project'{ projectId :: ProjectId, projectName :: String, inceptionDate :: date, initiator :: UUID}derive instance newtypeProject :: Newtype (Project' a) _type Project = Project' DateTimedata ProjectEvent= ProjectChange Projectinstance decodeJsonProject :: DecodeJson (Project' String) wheredecodeJson json = dox <- decodeJson jsonproject <- x .: "project"projectIdStr <- x .: "projectId"projectId <- ProjectId <$> (note "Failed to decode project UUID" $ parseUUID projectIdStr)projectName <- project .: "projectName"inceptionDate <- project .: "inceptionDate"initiatorStr <- project .: "initiator"initiator <- note "Failed to decode initiator UUID" $ parseUUID initiatorStrpure $ Project' { projectId, projectName, inceptionDate, initiator } - replacement in client/src/Main.purs at line 16
import Halogen.Aff as HAimport Halogen.Aff (runHalogenAff, awaitBody) - replacement in client/src/Main.purs at line 28
import Aftok.Types (System, liveSystem)import Aftok.Types (System, Project, ProjectEvent(..), liveSystem) - edit in client/src/Main.purs at line 33
import Aftok.Overview as Overview - replacement in client/src/Main.purs at line 37
main = HA.runHalogenAff dobody <- HA.awaitBodymain = runHalogenAff dobody <- awaitBody - replacement in client/src/Main.purs at line 44
mainComponent = component liveSystem login signup timeline projectoverview = Overview.apiCapabilitymainComponent = component liveSystem login signup timeline project overview - edit in client/src/Main.purs at line 56
| VOverview - edit in client/src/Main.purs at line 63
, VOverview <$ lit "overview" - edit in client/src/Main.purs at line 72
VOverview -> "overview" - edit in client/src/Main.purs at line 84
, selectedProject :: Maybe Project - edit in client/src/Main.purs at line 91
| ProjectAction ProjectEvent - edit in client/src/Main.purs at line 97
, overview :: Overview.Slot Unit - edit in client/src/Main.purs at line 103
_overview = SProxy :: SProxy "overview" - edit in client/src/Main.purs at line 114
-> Overview.Capability m - replacement in client/src/Main.purs at line 116
component system loginCap signupCap tlCap pCap = H.mkComponentcomponent system loginCap signupCap tlCap pCap ovCap = H.mkComponent - edit in client/src/Main.purs at line 130[24.9389][24.9389]
, selectedProject: Nothing - edit in client/src/Main.purs at line 146
VOverview ->HH.div_[ HH.slot _overview unit (Overview.component system ovCap pCap) st.selectedProject (Just <<< ProjectAction) ] - replacement in client/src/Main.purs at line 152
[ HH.slot _timeline unit (Timeline.component system tlCap pCap) unit absurd ][ HH.slot _timeline unit (Timeline.component system tlCap pCap) unit (Just <<< ProjectAction) ] - edit in client/src/Main.purs at line 168[2.1375]→[3.4407:4408](∅→∅),[3.2080]→[3.4407:4408](∅→∅),[3.2872]→[3.4407:4408](∅→∅),[3.4407]→[3.4407:4408](∅→∅),[3.4408]→[3.2873:2919](∅→∅),[3.2919]→[2.1376:1403](∅→∅)
LoginAction (Login.LoginComplete _) ->navigate VTimeline - edit in client/src/Main.purs at line 174[2.1456][24.9578]
LoginAction (Login.LoginComplete _) ->navigate VTimeline - edit in client/src/Main.purs at line 182
ProjectAction (ProjectChange p) ->H.modify_ (_ { selectedProject = Just p }) - replacement in client/src/Main.purs at line 205
[brand, logout][ brand, HH.ul [P.classes (ClassName <$> ["navbar-nav", "ml-auto"])] (map navItem nav), logout] - edit in client/src/Main.purs at line 213
nav :: Array NavItemnav = [ { label: "Overview", path: "overview" }, { label: "Timeline", path: "timeline" }] - edit in client/src/Main.purs at line 232
type NavTop ={ label :: String, items :: Array NavItem} - edit in client/src/Main.purs at line 238[3.2927]
type NavItem ={ label :: String, path :: String}navItem :: forall a s m. NavItem -> H.ComponentHTML a s mnavItem ni =HH.li[P.classes (ClassName <$> ["nav-item"]) ][ HH.a[ P.classes (ClassName <$> ["nav-link"]), P.href ("#" <> ni.path)][ HH.text ni.label ]]