Fix project selection, end log end on project switch.
[?]
Aug 19, 2020, 4:00 PM
ZIG57EE6RB22JGB3CT33EN2HVYCHCXBT5GROBTBMBLEMDTGQOOBQCDependencies
- [2]
QU5FW67RAdd project selection to time tracker. - [3]
4IQVQL4TAdded client for payouts endpoint. - [4]
EW2XN7KUUpdate docker build, clean up migration for payments tables. - [5]
JXG3FCXYUpgrade ps + halogen versions. - [6]
7VGYLTMUClean up schema version handling. - [7]
O5FVTOM6Undo JSON silliness, enable a couple more routes. - [8]
GMYPBCWEMake docker-compose work. - [9]
W35DDBFYFactor common JSON conversions up into client lib module. - [10]
ASF3UPJLAdd auction creation and bid handlers - [11]
BROSTG5KBeginning of modularization of server. - [12]
SEWTRB6SImplement payment request creation functions. - [13]
AL37SVTCImplement payments service endpoints. - [14]
NJNMO72SAdd zcash.com submodule and update client to modern halogen. - [15]
MGOF7IUFUpdate TASKS list to reflect completed projects. - [16]
Z3MK2PJ5Add GET handler for retrieving auction data. - [17]
O722AOKEAdd route to allow crediting of events to users/projects. - [18]
KNSI575VCleanup of EventLog types. - [19]
WRPIYG3EUse project listing functionality to check for whether we have a cookie. - [20]
HMDM3B55Implement core of payments/billing infrastructure. - [21]
BFZN4SUAMake timeline component work. - [22]
GCVQD44VCreate amends endpoint, switch to UUID primary keys - [23]
O227CEAVAdds storage of original event JSON for some DBOp constructors. - [24]
73NDXDEZBegin implementation of billing event persistence. - [25]
XTBSG4C7Adding serveJSON combinator to eliminate some boilerplate from handlers. - [26]
2XQD6KKKAdd invitation logic and clean up DBProg error handling. - [27]
A6HKMINBAttempting to improve JSON handling. - [28]
NEDDHXUKReformat via stylish-haskell - [29]
UILI6PILThe route-based logStart/logStop is nicer. - [30]
RPAJLHMTChange to use UUIDs instead of ints for primary keys. - [31]
HO2PFRABClient login now handles response correctly. - [32]
EFSXYZPOAutoformat everything with brittany. - [33]
IPG33FAWAdd billing daemon - [34]
B6HWAPDPModularize & update to recent haskoin. - [35]
Z7KS5XHHVery WIP. Wow. - [36]
QMRKFEPGRefactor QDB to use a free monad algebra instead. - [*]
IZEVQF62Work in progress replacing sqlite with postgres. - [*]
4U7F3CPITHE GREAT RENAMING OF THINGS! - [*]
ADMKQQGCInitial empty Snap project.
Change contents
- edit in client/src/Aftok/Project.purs at line 14
import Data.JSDate as JSDate - edit in client/src/Aftok/Project.purs at line 15
import Data.JSDate as JSDate - edit in client/src/Aftok/Project.purs at line 17
import Data.Newtype (class Newtype) - edit in client/src/Aftok/Project.purs at line 32
import Halogen.HTML.Core (ClassName(..)) - replacement in client/src/Aftok/Project.purs at line 36
import Effect.Class.Console (error)import Effect.Class.Console (log, error) - edit in client/src/Aftok/Project.purs at line 39
derive instance projectIdEq :: Eq ProjectIdderive instance newtypeProjectId :: Newtype ProjectId _ - edit in client/src/Aftok/Project.purs at line 51
derive instance newtypeProject :: Newtype (Project' a) _ - replacement in client/src/Aftok/Project.purs at line 90
in HH.select[E.onSelectedIndexChange (Just <<< Select)]([HH.option [P.selected true, P.disabled true] [HH.text "Select a project"]] <> map renderOption st.projects)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)] - replacement in client/src/Aftok/Project.purs at line 116
traverse_ H.raise (index projects i)log $ "Selected project index " <> show itraverse_ H.raise (index projects (i - 1)) - replacement in client/src/Aftok/Timeline.purs at line 13
import Data.Maybe (Maybe(..), maybe, isJust)import Data.Foldable (any)import Data.Maybe (Maybe(..), maybe, isJust, isNothing)import Data.Newtype (unwrap) - replacement in client/src/Aftok/Timeline.purs at line 58
type Interval =type Interval = - replacement in client/src/Aftok/Timeline.purs at line 63
type TimelineLimits =type TimelineLimits = - replacement in client/src/Aftok/Timeline.purs at line 69
type TimelineState =type TimelineState = - replacement in client/src/Aftok/Timeline.purs at line 88
type Slots =type Slots = - replacement in client/src/Aftok/Timeline.purs at line 99
componentcomponent - replacement in client/src/Aftok/Timeline.purs at line 101
. Capability Aff. Capability Aff - replacement in client/src/Aftok/Timeline.purs at line 104
component caps pcaps = H.mkComponentcomponent caps pcaps = H.mkComponent - replacement in client/src/Aftok/Timeline.purs at line 106
, render, eval: H.mkEval $ H.defaultEval, render, eval: H.mkEval $ H.defaultEval - replacement in client/src/Aftok/Timeline.purs at line 109
, initialize = Just Initialize, initialize = Just Initialize - replacement in client/src/Aftok/Timeline.purs at line 113
initialState _ =initialState _ = - replacement in client/src/Aftok/Timeline.purs at line 121[3.502]→[3.302724:302741](∅→∅),[2.3797]→[3.302724:302741](∅→∅),[3.302724]→[3.302724:302741](∅→∅),[3.302741]→[2.3798:3820](∅→∅)
render st =let lineForm =render 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 "Time Tracker"],HH.p[P.classes (ClassName <$> ["col-md-5", "text-muted", "text-center", "mx-auto"])][HH.text "Today's project timeline"],HH.div_[HH.slot _projectList unit (Project.projectListComponent pcaps) unit (Just <<< ProjectSelected)]],HH.div[P.classes (ClassName <$> if isNothing st.selectedProject then ["collapse"] else [])] - edit in client/src/Aftok/Timeline.purs at line 142
,P.disabled (isJust st.active) - edit in client/src/Aftok/Timeline.purs at line 148
,P.disabled (isNothing st.active) - replacement in client/src/Aftok/Timeline.purs at line 153
in HH.section[P.classes (ClassName <$> ["section-border", "border-primary"])]([HH.div[P.classes (ClassName <$> ["container-fluid", "pt-6"])][HH.h1[P.classes (ClassName <$> ["mb-0", "font-weight-bold", "text-center"])][HH.text "Time Tracker"],HH.p[P.classes (ClassName <$> ["col-md-5", "text-muted", "text-center", "mx-auto"])][HH.text "Today's project timeline"],HH.div_[HH.slot _projectList unit (Project.projectListComponent pcaps) unit (Just <<< ProjectSelected)]]] <> (if isJust st.selectedProject then lineForm else []))] - replacement in client/src/Aftok/Timeline.purs at line 162
limits =limits = - replacement in client/src/Aftok/Timeline.purs at line 177
ProjectSelected p ->ProjectSelected p -> doactive <- isJust <$> H.gets (_.active)currentProject <- H.gets (_.selectedProject)log $ "Active: " <> show active <> "; " <> show ((_.projectName) <<< unwrap <$> currentProject)log $ "Selected: " <> show ((_.projectName) <<< unwrap $ p)when (active && any (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject)(traverse_ logEnd currentProject) - edit in client/src/Aftok/Timeline.purs at line 187
let withProject (Project' p) = dologged <- lift $ caps.logStart p.projectIdcase logged ofLeft _ -> log "Failed to start timer."Right t -> H.modify_ (start t) - replacement in client/src/Aftok/Timeline.purs at line 188
log $ "Project selected? " <> show (isJust project)traverse_ withProject projecttraverse_ logStart project - replacement in client/src/Aftok/Timeline.purs at line 191
let withProject (Project' p) = dologged <- lift $ caps.logEnd p.projectIdcase logged ofLeft _ -> log "Failed to stop timer."Right t -> H.modify_ (stop t)project <- H.gets (_.selectedProject)traverse_ withProject projectcurrentProject <- H.gets (_.selectedProject)traverse_ logEnd currentProject - replacement in client/src/Aftok/Timeline.purs at line 198
lineHtmllogStart :: Project -> H.HalogenM TimelineState TimelineAction Slots output Aff UnitlogStart (Project' p) = dologged <- lift $ caps.logStart p.projectIdcase logged ofLeft _ -> log "Failed to start timer."Right t -> H.modify_ (start t)logEnd :: Project -> H.HalogenM TimelineState TimelineAction Slots output Aff UnitlogEnd (Project' p) = dologged <- lift $ caps.logEnd p.projectIdcase logged ofLeft _ -> log "Failed to stop timer."Right t -> H.modify_ (stop t)lineHtml - replacement in client/src/Aftok/Timeline.purs at line 227
intervalHtmlintervalHtml - replacement in client/src/Aftok/Timeline.purs at line 229
. TimelineLimits-> Interval. TimelineLimits-> Interval - replacement in client/src/Aftok/Timeline.purs at line 232
intervalHtml limits i =intervalHtml limits i = - replacement in client/src/Aftok/Timeline.purs at line 234
ileft = ilen limits.start i.startiwidth = ilen i.start i.endileft = ilen limits.start i.startiwidth = ilen i.start i.end - replacement in client/src/Aftok/Timeline.purs at line 239
[ CSS.style do[ CSS.style do - replacement in client/src/Aftok/Timeline.purs at line 260
start t s =start t s = - replacement in client/src/Aftok/Timeline.purs at line 265
stop t s =stop t s = - replacement in client/src/Aftok/Timeline.purs at line 271
refresh t s =refresh t s = - replacement in client/src/Aftok/Timeline.purs at line 273
, active = map (_ { end = t }) s.active, active = map (_ { end = t }) s.active - replacement in client/src/Aftok/Timeline.purs at line 277
ilen _start _end =ilen _start _end = - replacement in client/src/Aftok/Timeline.purs at line 281
logStart :: ProjectId -> Aff (Either TimelineError Instant)logStart (ProjectId pid) = doapiLogStart :: ProjectId -> Aff (Either TimelineError Instant)apiLogStart (ProjectId pid) = do - replacement in client/src/Aftok/Timeline.purs at line 292
logEnd :: ProjectId -> Aff (Either TimelineError Instant)logEnd (ProjectId pid) = doapiLogEnd :: ProjectId -> Aff (Either TimelineError Instant)apiLogEnd (ProjectId pid) = do - replacement in client/src/Aftok/Timeline.purs at line 304
apiCapability = { logStart, logEnd }apiCapability = { logStart: apiLogStart, logEnd: apiLogEnd } - replacement in client/src/Aftok/Timeline.purs at line 307
mockCapability =mockCapability = - replacement in lib/Aftok/Database/PostgreSQL.hs at line 589
[sql| SELECT p.id, p.project_name, p.inception_date, p.initiator_id, p.depreciation_fn[sql| SELECT DISTINCT ON (p.inception_date, p.id) p.id, p.project_name, p.inception_date, p.initiator_id, p.depreciation_fn - replacement in lib/Aftok/Database/PostgreSQL.hs at line 592
OR p.initiator_id = ? |]OR p.initiator_id = ?ORDER BY p.inception_date, p.id |] - edit in lib/Aftok/Json.hs at line 16
import qualified Control.Lens as L - edit in lib/Aftok/Json.hs at line 44
import Aftok.Database ( KeyedLogEntry ) - replacement in lib/Aftok/Json.hs at line 131
idValue :: forall a . Lens' a UUID -> a -> ValueidValue :: forall a . Getter a UUID -> a -> Value - replacement in lib/Aftok/Json.hs at line 134
idJSON :: forall a . Text -> Lens' a UUID -> a -> ValueidJSON :: forall a . Text -> Getter a UUID -> a -> Value - replacement in lib/Aftok/Json.hs at line 137
qdbJSON :: Text -> (Lens' a UUID) -> (b -> Value) -> (a, b) -> ValueqdbJSON name l f (xid, x) =v1 $ obj [(name <> "Id") .= idValue l xid, name .= f x]qdbJSON :: Text -> Getter a UUID -> Getter a Value -> a -> ValueqdbJSON name _id _value x =v1 $ obj[(name <> "Id") .= idValue _id x, name .= (x ^. _value)] - replacement in lib/Aftok/Json.hs at line 155
qdbProjectJSON = qdbJSON "project" _ProjectId projectJSONqdbProjectJSON = qdbJSON "project" (_1 . _ProjectId) (_2 . L.to projectJSON) - replacement in lib/Aftok/Json.hs at line 271
v2$ let widxRec :: (CreditTo (NetworkId, Address), NonEmpty Interval) -> ValuewidxRec (c, l) = object[ "creditTo" .= creditToJSON nmode c, "intervals" .= (intervalJSON <$> L.toList l)]in obj $ ["workIndex" .= fmap widxRec (MS.assocs widx)]v2 $ obj ["workIndex" .= fmap widxRec (MS.assocs widx)]wherewidxRec :: (CreditTo (NetworkId, Address), NonEmpty Interval) -> ValuewidxRec (c, l) = object[ "creditTo" .= creditToJSON nmode c, "intervals" .= (intervalJSON <$> L.toList l)] - replacement in lib/Aftok/Json.hs at line 287
logEntryJSON nmode (LogEntry c ev m) = v2 $ objlogEntryJSON nmode le = v2 $ obj (logEntryFields nmode le)logEntryFields :: NetworkMode -> LogEntry (NetworkId, Address) -> [Pair]logEntryFields nmode (LogEntry c ev m) = - edit in lib/Aftok/Json.hs at line 296
keyedLogEntryJSON :: NetworkMode -> (EventId, KeyedLogEntry (NetworkId, Address)) -> ValuekeyedLogEntryJSON nmode le = qdbJSON "event" (_1 . _EventId) (_2 . _3 . to (logEntryJSON nmode)) le - replacement in lib/Aftok/Json.hs at line 320
qdbBillableJSON = qdbJSON "billable" B._BillableId billableJSONqdbBillableJSON = qdbJSON "billable" (_1 . B._BillableId) (_2 . to billableJSON) - edit in server/Aftok/Snaplet/WorkLog.hs at line 1
{-# LANGUAGE TupleSections #-} - replacement in server/Aftok/Snaplet/WorkLog.hs at line 36
logWorkHandler :: (C.UTCTime -> LogEvent) -> S.Handler App App EventIdlogWorkHandler :: (C.UTCTime -> LogEvent) -> S.Handler App App (EventId, KeyedLogEntry BTCNet) - replacement in server/Aftok/Snaplet/WorkLog.hs at line 52
Right entry -> snapEval $ createEvent pid uid (entry timestamp)Right entry -> doeid <- snapEval $ createEvent pid uid (entry timestamp)ev <- snapEval $ findEvent eidmaybe(snapError 500 $ "An error occured retrieving the newly created event record.")(pure . (eid,))ev - replacement in server/Main.hs at line 79
logWorkRoute f = serveJSON eventIdJSON $ method POST (logWorkHandler f)logWorkRoute f =serveJSON (keyedLogEntryJSON nmode) $ method POST (logWorkHandler f)