Merge remote-tracking branch 'origin/release/next-userspace'

This commit is contained in:
Liam Fitzgerald 2020-12-18 14:04:08 +10:00
commit a66d0fc2ba
No known key found for this signature in database
GPG Key ID: D390E12C61D1CFFB
20 changed files with 9736 additions and 2422 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
:: hark-graph-hook: notifications for graph-store [landscape]
::
/- store=hark-store, post, group-store, metadata-store, hook=hark-graph-hook
/+ resource, metadata, default-agent, dbug, graph-store, graph, grouplib=group
/- post, group-store, metadata-store, hook=hark-graph-hook, store=hark-store
/+ resource, metadata, default-agent, dbug, graph-store, graph, grouplib=group, store=hark-store
::
::
~% %hark-graph-hook-top ..part ~
@ -19,31 +19,27 @@
==
::
+$ notif-kind
[name=@t parent-lent=@ud mode=?(%each %count) watch=?]
[name=@t parent-lent=@ud mode=?(%each %count %none) watch=?]
::
++ scry
|* [[our=@p now=@da] =mold p=path]
?> ?=(^ p)
?> ?=(^ t.p)
.^(mold i.p (scot %p our) i.t.p (scot %da now) t.t.p)
::
++ scry-conversion
|= [[our=@p now=@da] desk=term =mark]
~+
%^ scry [our now]
tube:clay
/cc/[desk]/[mark]/notification-kind
::
--
::
=| state-0
=* state -
::
=>
|_ =bowl:gall
::
++ scry
|* [=mold p=path]
?> ?=(^ p)
?> ?=(^ t.p)
.^(mold i.p (scot %p our.bowl) i.t.p (scot %da now.bowl) t.t.p)
::
++ give
|= [paths=(list path) =update:hook]
^- (list card)
[%give %fact paths hark-graph-hook-update+!>(update)]~
::
++ watch-graph
^- card
[%pass /graph %agent [our.bowl %graph-store] %watch /updates]
--
=<
%- agent:dbug
^- agent:gall
~% %hark-graph-hook-agent ..card ~
@ -162,8 +158,38 @@
(graph-update !<(update:graph-store q.cage.sign))
[cards this]
==
::
++ graph-update
|= =update:graph-store
^- (quip card _state)
?+ -.q.update `state
%add-graph (add-graph resource.q.update)
::
?(%remove-graph %archive-graph)
(remove-graph resource.q.update)
::
%add-nodes
=* rid resource.q.update
(check-nodes ~(val by nodes.q.update) rid)
==
::
++ remove-graph
|= rid=resource
=/ unwatched
%- ~(gas in *_watching)
%+ skim ~(tap in watching)
|= [r=resource idx=index:graph-store]
=(r rid)
:_ state(watching (~(dif in watching) unwatched))
^- (list card)
:- (poke-hark:ha %remove-graph rid)
%- zing
%+ turn ~(tap in unwatched)
|= [r=resource =index:graph-store]
(give:ha ~[/updates] %ignore r index)
::
++ add-graph
|= [rid=resource =graph:graph-store]
|= rid=resource
^- (quip card _state)
=/ group-rid=(unit resource)
(group-from-app-resource:met %graph rid)
@ -176,146 +202,29 @@
|(is-hidden &(watch-on-self =(our.bowl entity.rid)))
?. should-watch
`state
:- (give:ha ~[/updates] %listen [rid ~])
state(watching (~(put in watching) [rid ~]))
=/ graph=graph:graph-store :: graph in subscription is bunted
(get-graph-mop:gra rid)
=/ node=(unit node:graph-store)
(bind (peek:orm:graph-store graph) |=([@ =node:graph-store] node))
=^ cards state
(check-nodes (drop node) rid)
:_ state(watching (~(put in watching) [rid ~]))
(weld cards (give:ha ~[/updates] %listen [rid ~]))
::
++ graph-update
|= =update:graph-store
^- (quip card _state)
?: ?=(%add-graph -.q.update)
(add-graph resource.q.update graph.q.update)
?. ?=(%add-nodes -.q.update)
[~ state]
=* rid resource.q.update
(check-nodes ~(tap by nodes.q.update) rid)
::
++ check-nodes
|= $: nodes=(list [p=index:graph-store q=node:graph-store])
|= $: nodes=(list node:graph-store)
rid=resource
==
=/ group=resource
(need (group-from-app-resource:met %graph rid))
=/ =metadata:metadata-store
(need (peek-metadata:met %graph group rid))
=+ %+ scry:ha
,mark=(unit mark)
/gx/graph-store/graph-mark/(scot %p entity.rid)/[name.rid]/noun
=+ %+ scry:ha
,=tube:clay
/cc/[q.byk.bowl]/[(fall mark %graph-validator-link)]/notification-kind
=| cards=(list card)
|^
?~ nodes
[cards state]
=* index p.i.nodes
=* node q.i.nodes
=^ node-cards state
(check-node node tube)
%_ $
nodes t.nodes
cards (weld node-cards cards)
==
::
++ check-node-children
|= [=node:graph-store =tube:clay]
^- (quip card _state)
?: ?=(%empty -.children.node)
[~ state]
=/ children=(list [=atom =node:graph-store])
(tap:orm:graph-store p.children.node)
=| cards=(list card)
|- ^- (quip card _state)
?~ children
[cards state]
=^ new-cards state
(check-node node.i.children tube)
%_ $
cards (weld cards new-cards)
children t.children
==
::
++ check-node
|= [=node:graph-store =tube:clay]
^- (quip card _state)
=^ child-cards state
(check-node-children node tube)
=+ !< notif-kind=(unit notif-kind)
(tube !>([0 post.node]))
?~ notif-kind
[child-cards state]
=/ desc=@t
?: (is-mention contents.post.node)
%mention
name.u.notif-kind
=/ parent=index:post
(scag parent-lent.u.notif-kind index.post.node)
=/ notif-index=index:store
[%graph group rid module.metadata desc parent]
?: =(our.bowl author.post.node)
=^ self-cards state
(self-post node notif-index [mode watch]:u.notif-kind)
:_ state
(weld child-cards self-cards)
:_ state
%+ weld child-cards
%+ weld
%^ update-unread-count
mode.u.notif-kind notif-index
[time-sent index]:post.node
?. ?| =(desc %mention)
(~(has in watching) [rid parent])
==
~
=/ =contents:store
[%graph (limo post.node ~)]
~[(add-unread notif-index [time-sent.post.node %.n contents])]
::
++ is-mention
|= contents=(list content:post)
^- ?
?. mentions %.n
?~ contents %.n
?. ?=(%mention -.i.contents)
$(contents t.contents)
?: =(our.bowl ship.i.contents)
%.y
$(contents t.contents)
::
++ self-post
|= $: =node:graph-store
=index:store
mode=?(%count %each)
watch=?
==
^- (quip card _state)
=| cards=(list card)
=? cards ?=(%count mode)
:_ cards
(poke-hark %read-count index)
?. &(watch watch-on-self)
[cards state]
:- cards
state(watching (~(put in watching) [rid index.post.node]))
::
++ poke-hark
|= =action:store
^- card
=- [%pass / %agent [our.bowl %hark-store] %poke -]
hark-action+!>(action)
::
++ update-unread-count
|= [mode=?(%count %each %none) =index:store time=@da ref=index:graph-store]
?- mode
%count ~[(poke-hark %unread-count index time)]
%each ~[(poke-hark %unread-each index ref time)]
%none ~
==
::
++ add-unread
|= [=index:store =notification:store]
(poke-hark %add-note index notification)
::
--
=/ group=(unit resource)
(group-from-app-resource:met %graph rid)
?~ group
~& no-group+rid
`state
=/ metadata=(unit metadata:metadata-store)
(peek-metadata:met %graph u.group rid)
?~ metadata `state
abet:check:(abed:handle-update:ha rid nodes u.group module.u.metadata)
--
::
++ on-peek on-peek:def
@ -334,4 +243,160 @@
==
++ on-fail on-fail:def
--
::
|_ =bowl:gall
::
::
++ give
|= [paths=(list path) =update:hook]
^- (list card)
[%give %fact paths hark-graph-hook-update+!>(update)]~
::
++ watch-graph
^- card
[%pass /graph %agent [our.bowl %graph-store] %watch /updates]
::
++ poke-hark
|= =action:store
^- card
=- [%pass / %agent [our.bowl %hark-store] %poke -]
hark-action+!>(action)
::
++ is-mention
|= contents=(list content:post)
^- ?
?. mentions %.n
?~ contents %.n
?. ?=(%mention -.i.contents)
$(contents t.contents)
?: =(our.bowl ship.i.contents)
%.y
$(contents t.contents)
::
++ handle-update
|_ $: rid=resource :: input
updates=(list node:graph-store)
group=resource
module=term
hark-pokes=(list action:store) :: output
new-watches=(list index:graph-store)
==
++ update-core .
::
++ abed
|= [r=resource upds=(list node:graph-store) grp=resource mod=term]
update-core(rid r, updates upds, group grp, module mod)
::
++ get-conversion
^- tube:clay
=+ %^ scry [our now]:bowl
,mark=(unit mark)
/gx/graph-store/graph-mark/(scot %p entity.rid)/[name.rid]/noun
?~ mark
|=(v=vase !>(~))
(scry-conversion [our now]:bowl q.byk.bowl u.mark)
::
++ abet
^- (quip card _state)
:_ state(watching (~(uni in watching) (silt (turn new-watches (lead rid)))))
^- (list card)
%+ welp (turn (flop hark-pokes) poke-hark)
%- zing
%+ turn (flop new-watches)
|=(=index:graph-store (give ~[/updates] [%listen rid index]))
::
++ hark
|= =action:store
^+ update-core
update-core(hark-pokes [action hark-pokes])
::
++ new-watch
|= =index:graph-store
update-core(new-watches [index new-watches])
::
++ check
|- ^+ update-core
?~ updates
update-core
=/ core=_update-core
(check-node i.updates)
=. updates.core t.updates
$(update-core core)
::
++ check-node-children
|= =node:graph-store
^+ update-core
?: ?=(%empty -.children.node)
update-core
=/ children=(list [=atom =node:graph-store])
(tap:orm:graph-store p.children.node)
|- ^+ update-core
?~ children
update-core
=. update-core (check-node node.i.children)
$(children t.children)
::
++ check-node
|= =node:graph-store
^+ update-core
=. update-core (check-node-children node)
=+ !< notif-kind=(unit notif-kind)
(get-conversion !>([0 post.node]))
?~ notif-kind
update-core
=/ desc=@t
?: (is-mention contents.post.node)
%mention
name.u.notif-kind
=* not-kind u.notif-kind
=/ parent=index:post
(scag parent-lent.not-kind index.post.node)
=/ notif-index=index:store
[%graph group rid module desc parent]
?: =(our.bowl author.post.node)
(self-post node notif-index [mode watch]:not-kind)
=. update-core
(update-unread-count not-kind notif-index [time-sent index]:post.node)
=? update-core
?| =(desc %mention)
(~(has in watching) [rid parent])
==
=/ =contents:store
[%graph (limo post.node ~)]
(add-unread notif-index [time-sent.post.node %.n contents])
update-core
::
++ update-unread-count
|= [=notif-kind =index:store time=@da ref=index:graph-store]
=/ =stats-index:store
(to-stats-index:store index)
?- mode.notif-kind
%count (hark %unread-count stats-index time)
%each (hark %unread-each stats-index ref time)
%none update-core
==
::
++ self-post
|= $: =node:graph-store
=index:store
mode=?(%count %each %none)
watch=?
==
^+ update-core
?: ?=(%none mode) update-core
=/ =stats-index:store
(to-stats-index:store index)
=. update-core
(hark %seen-index time-sent.post.node stats-index)
=? update-core ?=(%count mode)
(hark %read-count stats-index)
=? update-core &(watch watch-on-self)
(new-watch index.post.node)
update-core
::
++ add-unread
|= [=index:store =notification:store]
(hark %add-note index notification)
::
--
--

View File

@ -10,7 +10,7 @@
:: Usefull for non-linear, low-volume applications, i.e. blogs,
:: collections
::
/- post, group-store, metadata-store
/- post, group-store, metadata-store, store=hark-store
/+ resource, metadata, default-agent, dbug, graph-store, graphl=graph, verb, store=hark-store
::
::
@ -19,29 +19,31 @@
+$ card card:agent:gall
+$ versioned-state
$% state:state-zero:store
state-1
state:state-one:store
state-2
==
+$ unread-stats
[indices=(set index:graph-store) last=@da]
::
+$ state-1
$: %1
unreads-each=(jug index:store index:graph-store)
unreads-count=(map index:store @ud)
last-seen=(map index:store @da)
+$ state-2
$: %2
unreads-each=(jug stats-index:store index:graph-store)
unreads-count=(map stats-index:store @ud)
last-seen=(map stats-index:store @da)
=notifications:store
archive=notifications:store
current-timebox=@da
dnd=_|
==
::
+$ inflated-state
$: state-1
$: state-2
cache
==
:: $cache: useful to have precalculated, but can be derived from state
:: albeit expensively
+$ cache
$: by-index=(jug index:store @da)
$: by-index=(jug stats-index:store @da)
~
==
::
@ -76,15 +78,30 @@
=| cards=(list card)
|^
?- -.old
%2
:- cards
this(-.state old, +.state (inflate-cache:ha old))
::
%1
[cards this(+.state (inflate-cache:ha old), -.state old)]
%_ $
::
old
%* . *state-2
unreads-each ((convert-unread ,(set index:graph-store)) uni-by unreads-each.old)
unreads-count ((convert-unread ,@ud) add unreads-count.old)
last-seen ((convert-unread ,@da) max last-seen.old)
notifications notifications.old
archive archive.old
current-timebox current-timebox.old
dnd dnd.old
==
==
::
%0
%_ $
::
old
%* . *state-1
%* . *state:state-one:store
notifications (convert-notifications-1 notifications.old)
archive (convert-notifications-1 archive.old)
current-timebox current-timebox.old
@ -92,6 +109,28 @@
==
==
==
:: discard publish edits
++ uni-by
|= [a=(set index:graph-store) b=(set index:graph-store)]
=/ merged
(~(uni in a) b)
%- ~(gas in *(set index:graph-store))
%+ skip ~(tap in merged)
|=(=index:graph-store &(=((lent index) 3) !=(-:(flop index) 1)))
::
++ convert-unread
|* value=mold
|= [combine=$-([value value] value) unreads=(map index:store value)]
^- (map stats-index:store value)
%+ roll
~(tap in unreads)
|= [[=index:store val=value] out=(map stats-index:store value)]
=/ old=value
(~(gut by unreads) index (combine))
=/ =stats-index:store
(to-stats-index:store index)
(~(put by out) stats-index (combine old val))
::
++ convert-notifications-1
|= old=notifications:state-zero:store
%+ gas:orm *notifications:store
@ -159,48 +198,35 @@
^- update:store
:- %more
^- (list update:store)
:+ give-unreads
[%set-dnd dnd]
%+ weld
%+ turn
(tap-nonempty:ha archive)
(timebox-update &)
%+ turn
(tap-nonempty:ha notifications)
(timebox-update |)
:- give-unreads
[%set-dnd dnd]~
::
++ give-since-unreads
^- (list [index:store index-stats:store])
^- (list [stats-index:store stats:store])
%+ turn
~(tap by unreads-count)
|= [=index:store count=@ud]
?> ?=(%graph -.index)
:* index
~(wyt in (~(gut by by-index) index ~))
|= [=stats-index:store count=@ud]
?> ?=(%graph -.stats-index)
:* stats-index
~(wyt in (~(gut by by-index) stats-index ~))
[%count count]
(~(gut by last-seen) index *time)
(~(gut by last-seen) stats-index *time)
==
++ give-each-unreads
^- (list [index:store index-stats:store])
^- (list [stats-index:store stats:store])
%+ turn
~(tap by unreads-each)
|= [=index:store indices=(set index:graph-store)]
:* index
~(wyt in (~(gut by by-index) index ~))
|= [=stats-index:store indices=(set index:graph-store)]
:* stats-index
~(wyt in (~(gut by by-index) stats-index ~))
[%each indices]
(~(gut by last-seen) index *time)
(~(gut by last-seen) stats-index *time)
==
::
++ give-unreads
^- update:store
:- %unreads
(weld give-each-unreads give-since-unreads)
::
++ timebox-update
|= archived=?
|= [time=@da =timebox:store]
^- update:store
[%timebox time archived ~(tap by timebox)]
--
::
++ on-peek
@ -238,209 +264,14 @@
=^ cards state
?+ mark (on-poke:def mark vase)
%hark-action (hark-action !<(action:store vase))
%noun ~& +.state [~ state]
%noun ~& +.state [~ state]
==
[cards this]
::
++ hark-action
|= =action:store
^- (quip card _state)
|^
?- -.action
%add-note (add-note +.action)
%archive (do-archive +.action)
::
%read-each (read-each +.action)
%unread-each (unread-each +.action)
::
%read-count (read-count +.action)
%unread-count (unread-count +.action)
::
%read-note (read-note +.action)
%unread-note (unread-note +.action)
::
%read-all read-all
::
%set-dnd (set-dnd +.action)
%seen seen
==
::
++ add-note
|= [=index:store =notification:store]
^- (quip card _state)
=/ =timebox:store
(gut-orm:ha notifications current-timebox)
=/ existing-notif
(~(get by timebox) index)
=/ new=notification:store
?~ existing-notif
notification
(merge-notification:ha u.existing-notif notification)
=/ new-read=?
?~ existing-notif
%.y
read.u.existing-notif
=. read.new %.n
=/ new-timebox=timebox:store
(~(put by timebox) index new)
:- (give:ha [/updates]~ %added current-timebox index new)
%_ state
+ ?.(new-read +.state (upd-unreads:ha index current-timebox %.n))
notifications (put:orm notifications current-timebox new-timebox)
==
::
++ do-archive
|= [time=@da =index:store]
^- (quip card _state)
=/ =timebox:store
(gut-orm:ha notifications time)
=/ =notification:store
(~(got by timebox) index)
=/ new-timebox=timebox:store
(~(del by timebox) index)
:- (give:ha [/updates]~ %archive time index)
%_ state
+ ?.(read.notification (upd-unreads:ha index time %.y) +.state)
::
notifications
(put:orm notifications time new-timebox)
::
archive
%^ jub-orm:ha archive time
|= archive-box=timebox:store
^- timebox:store
(~(put by archive-box) index notification(read %.y))
==
::
++ unread-each
|= [=index:store unread=index:graph-store time=@da]
:- (give:ha ~[/updates] %unread-each index unread time)
%_ state
unreads-each
%+ jub index
|= indices=(set index:graph-store)
(~(put in indices) unread)
::
last-seen
(~(put by last-seen) index time)
==
::
++ jub
|= [=index:store f=$-((set index:graph-store) (set index:graph-store))]
^- (jug index:store index:graph-store)
=/ val=(set index:graph-store)
(~(gut by unreads-each) index ~)
(~(put by unreads-each) index (f val))
::
++ read-each
|= [=index:store ref=index:graph-store]
=/ to-dismiss=(list @da)
%+ skim
~(tap in (~(get ju by-index) index))
|= time=@da
=/ =timebox:store
(gut-orm notifications time)
=/ not=(unit notification:store)
(~(get by timebox) index)
?~ not %.n
?> ?=(%graph -.contents.u.not)
(lien list.contents.u.not |=(p=post:post =(index.p ref)))
=| cards=(list card)
|-
?^ to-dismiss
=^ crds state
(read-note i.to-dismiss index)
$(cards (weld cards crds), to-dismiss t.to-dismiss)
:- (weld cards (give:ha ~[/updates] %read-each index ref))
%_ state
::
unreads-each
%+ jub index
|= indices=(set index:graph-store)
(~(del in indices) ref)
==
::
++ read-note
|= [time=@da =index:store]
^- (quip card _state)
:- (give:ha [/updates]~ %read-note time index)
%_ state
+ (upd-unreads:ha index time %.y)
notifications (change-read-status:ha time index %.y)
==
::
++ unread-note
|= [time=@da =index:store]
^- (quip card _state)
:- (give:ha [/updates]~ %unread-note time index)
%_ state
+ (upd-unreads:ha index time %.n)
notifications (change-read-status:ha time index %.n)
==
::
++ read-count
|= =index:store
^- (quip card _state)
=^ cards state
(read-index index)
:- %+ weld cards
(give:ha [/updates]~ %read-count index)
%_ state
unreads-count (~(put by unreads-count) index 0)
==
::
++ read-boxes
|= [boxes=(set @da) =index:store]
^- (quip card _state)
=/ boxes=(list @da)
~(tap in boxes)
=| crds=(list card)
|-
?~ boxes [crds state]
=* box i.boxes
=^ cards state
(read-note box index)
$(boxes t.boxes, crds (welp crds cards))
::
++ read-index
|= =index:store
^- (quip card _state)
=/ boxes=(set @da)
(~(get ju by-index) index)
=^ cards state
(read-boxes boxes index)
:_ state
%+ welp cards
(give:ha ~[/updates] %read-index index)
::
++ read-all
^- (quip card _state)
`state
::
++ unread-count
|= [=index:store time=@da]
^- (quip card _state)
:- (give:ha [/updates]~ %unread-count index time)
=/ curr=@ud
(~(gut by unreads-count) index 0)
%_ state
last-seen (~(put by last-seen) index time)
unreads-count (~(put by unreads-count) index +(curr))
==
::
++ seen
^- (quip card _state)
:_ state(current-timebox now.bowl)
:~ cancel-autoseen:ha
autoseen-timer:ha
==
::
++ set-dnd
|= d=?
^- (quip card _state)
:_ state(dnd d)
(give:ha [/updates]~ %set-dnd d)
--
abet:translate:(abed:poke-engine:ha action)
--
::
++ on-agent on-agent:def
@ -459,35 +290,291 @@
--
|_ =bowl:gall
+* met ~(. metadata bowl)
++ poke-engine
|_ [in=action:store out=(list update:store) cards=(list card)]
++ poke-core .
::
++ abed
|= =action:store poke-core(in action)
::
++ abet
^- (quip card _state)
:_ state
%+ snoc (flop cards)
[%give %fact ~[/updates] %hark-update !>([%more (flop out)])]
::
++ give
|= =update:store poke-core(out [update out])
::
++ emit
|= =card poke-core(cards [card cards])
::
++ translate
^+ poke-core
?+ -.in poke-core
::
%add-note (add-note +.in)
%archive (do-archive +.in)
::
%unread-count (unread-count +.in)
%read-count (read-count +.in)
::
%read-each (read-each +.in)
%unread-each (unread-each +.in)
::
%read-note (read-note +.in)
%unread-note (unread-note +.in)
::
%seen-index (seen-index +.in)
%remove-graph (remove-graph +.in)
%set-dnd (set-dnd +.in)
%seen seen
==
::
:: +| %note
::
:: notification tracking
++ upd-cache
|= [read=? time=@da =index:store]
poke-core(+.state (^upd-cache read time index))
::
++ put-notifs
|= [time=@da =timebox:store]
poke-core(notifications (put:orm notifications time timebox))
::
++ add-note
|= [=index:store =notification:store]
^+ poke-core
=/ =timebox:store
(gut-orm notifications current-timebox)
=/ existing-notif
(~(get by timebox) index)
=/ new=notification:store
(merge-notification existing-notif notification)
=/ new-read=?
?~ existing-notif %.y
read.u.existing-notif
=/ new-timebox=timebox:store
(~(put by timebox) index new)
=. poke-core (put-notifs current-timebox new-timebox)
=? poke-core new-read
(upd-cache %.n current-timebox index)
(give %added current-timebox index new)
::
++ do-archive
|= [time=@da =index:store]
^+ poke-core
=/ =timebox:store
(gut-orm notifications time)
=/ =notification:store
(~(got by timebox) index)
=/ new-timebox=timebox:store
(~(del by timebox) index)
=? poke-core !read.notification
(upd-cache %.y time index)
=. poke-core
(put-notifs time new-timebox)
=. archive
%^ jub-orm archive time
|= archive-box=timebox:store
(~(put by archive-box) index notification(read %.y))
(give %archive time index)
::
++ change-read-status
|= [time=@da =index:store read=?]
=. poke-core (upd-cache read time index)
%_ poke-core
notifications
%^ jub-orm notifications time
|= =timebox:store
%+ ~(jab by timebox) index
|= n=notification:store
?>(!=(read read.n) n(read read))
==
::
++ read-note
|= [time=@da =index:store]
%. [%read-note time index]
give:(change-read-status time index %.y)
::
++ unread-note
|= [time=@da =index:store]
%. [%unread-note time index]
give:(change-read-status time index %.n)
::
:: +| %each
::
:: each unread tracking
::
++ unread-each
|= [=stats-index:store unread=index:graph-store time=@da]
=. poke-core (seen-index time stats-index)
%+ jub-unreads-each:(give %unread-each stats-index unread time)
stats-index
|= indices=(set index:graph-store)
(~(put ^in indices) unread)
::
++ read-index-each
|= [=stats-index:store ref=index:graph-store]
%+ read-index stats-index
%+ skim
~(tap ^in (~(get ju by-index) stats-index))
|= time=@da
=/ =timebox:store
(gut-orm notifications time)
%+ roll
~(tap ^in timebox)
|= [[=index:store not=notification:store] out=?]
?: out out
?. (stats-index-is-index:store stats-index index) out
?. ?=(%graph -.index) out
?. ?=(%graph -.contents.not) out
(lien list.contents.not |=(p=post:post =(index.p ref)))
::
++ read-each
|= [=stats-index:store ref=index:graph-store]
=. poke-core (read-index-each stats-index ref)
%+ jub-unreads-each:(give %read-each stats-index ref)
stats-index
|= indices=(set index:graph-store)
(~(del ^in indices) ref)
::
++ jub-unreads-each
|= $: =stats-index:store
f=$-((set index:graph-store) (set index:graph-store))
==
poke-core(unreads-each (jub stats-index f))
::
++ unread-count
|= [=stats-index:store time=@da]
=/ new-count
+((~(gut by unreads-count) stats-index 0))
=. unreads-count
(~(put by unreads-count) stats-index new-count)
(seen-index:(give %unread-count stats-index time) time stats-index)
::
++ read-count
|= =stats-index:store
=. unreads-count (~(put by unreads-count) stats-index 0)
=/ times=(list @da)
~(tap ^in (~(get ju by-index) stats-index))
(give:(read-index stats-index times) %read-count stats-index)
::
++ read-index
|= [=stats-index:store times=(list @da)]
|-
?~ times poke-core
=/ core
(read-stats-index i.times stats-index)
$(poke-core core, times t.times)
::
++ read-stats-index
|= [time=@da =stats-index:store]
=/ keys
~(tap ^in ~(key by (gut-orm notifications time)))
|- ^+ poke-core
?~ keys
poke-core
?. (stats-index-is-index:store stats-index i.keys)
$(keys t.keys)
=/ core
(read-note time i.keys)
$(poke-core core, keys t.keys)
::
++ seen-index
|= [time=@da =stats-index:store]
=/ new-time=@da
(max time (~(gut by last-seen) stats-index 0))
=. last-seen
(~(put by last-seen) stats-index new-time)
(give %seen-index new-time stats-index)
::
++ remove-graph
|= rid=resource
|^
=/ indices get-stats-indices
=. poke-core
(give %remove-graph rid)
=. poke-core
(remove-notifications indices)
=. unreads-count
((dif-map-by-key ,@ud) unreads-count indices)
=. unreads-each
%+ (dif-map-by-key ,(set index:graph-store))
unreads-each indices
=. last-seen
((dif-map-by-key ,@da) last-seen indices)
=. by-index
((dif-map-by-key ,(set @da)) by-index indices)
poke-core
::
++ get-stats-indices
%- ~(gas ^in *(set stats-index:store))
%+ skim
;: weld
~(tap ^in ~(key by unreads-count))
~(tap ^in ~(key by last-seen))
~(tap ^in ~(key by unreads-each))
~(tap ^in ~(key by by-index))
==
|= =stats-index:store
?. ?=(%graph -.stats-index) %.n
=(graph.stats-index rid)
::
++ dif-map-by-key
|* value=mold
|= [=(map stats-index:store value) =(set stats-index:store)]
=/ to-remove ~(tap ^in set)
|-
?~ to-remove map
=. map
(~(del by map) i.to-remove)
$(to-remove t.to-remove)
::
++ remove-notifications
|= =(set stats-index:store)
^+ poke-core
=/ indices
~(tap ^in set)
|-
?~ indices poke-core
=/ times=(list @da)
~(tap ^in (~(get ju by-index) i.indices))
=. poke-core
(read-index i.indices times)
$(indices t.indices)
--
::
++ seen
=> (emit cancel-autoseen)
=> (emit autoseen-timer)
poke-core(current-timebox now.bowl)
::
++ set-dnd
|= d=?
(give:poke-core(dnd d) %set-dnd d)
--
::
++ merge-notification
|= [existing=notification:store new=notification:store]
|= [existing=(unit notification:store) new=notification:store]
^- notification:store
?- -.contents.existing
?~ existing new
?- -.contents.u.existing
::
%graph
?> ?=(%graph -.contents.new)
existing(read %.n, list.contents (weld list.contents.existing list.contents.new))
u.existing(read %.n, list.contents (weld list.contents.u.existing list.contents.new))
::
%group
?> ?=(%group -.contents.new)
existing(read %.n, list.contents (weld list.contents.existing list.contents.new))
u.existing(read %.n, list.contents (weld list.contents.u.existing list.contents.new))
==
::
++ change-read-status
|= [time=@da =index:store read=?]
^+ notifications
%^ jub-orm notifications time
|= =timebox:store
%+ ~(jab by timebox) index
|= =notification:store
?> !=(read read.notification)
notification(read read)
:: +key-orm: +key:by for ordered maps
++ key-orm
|= =notifications:store
^- (list @da)
(turn (tap:orm notifications) |=([key=@da =timebox:store] key))
(turn (tap:orm notifications) |=([@da *] +<-))
:: +jub-orm: combo +jab/+gut for ordered maps
:: TODO: move to zuse.hoon
++ jub-orm
@ -496,6 +583,12 @@
=/ =timebox:store
(fun (gut-orm notifications time))
(put:orm notifications time timebox)
++ jub
|= [=stats-index:store f=$-((set index:graph-store) (set index:graph-store))]
^- (jug stats-index:store index:graph-store)
=/ val=(set index:graph-store)
(~(gut by unreads-each) stats-index ~)
(~(put by unreads-each) stats-index (f val))
:: +gut-orm: +gut:by for ordered maps
:: TODO: move to zuse.hoon
++ gut-orm
@ -523,47 +616,32 @@
^- (list card)
[%give %fact paths [%hark-update !>(update)]]~
::
++ upd-unreads
|= [=index:store time=@da read=?]
^+ +.state
%_ +.state
::
by-index
%. [index time]
?: read
~(del ju by-index)
~(put ju by-index)
==
::
++ group-for-index
|= =index:store
^- (unit resource)
?. ?=(%graph -.index)
~
`group.index
::
++ give-dirtied-unreads
|= [=index:store =update:store]
^- (list card)
=/ group
(group-for-index index)
?~ group ~
(give ~[group+(en-path:resource u.group)] update)
::
++ tap-nonempty
|= =notifications:store
^- (list [@da timebox:store])
%+ skim (tap:orm notifications)
|=([@da =timebox:store] !=(~(wyt by timebox) 0))
::
++ upd-cache
|= [read=? time=@da =index:store]
^+ +.state
%_ +.state
::
by-index
%. [(to-stats-index:store index) time]
?: read
~(del ju by-index)
~(put ju by-index)
==
::
++ inflate-cache
|= state-1
|= state-2
^+ +.state
=/ nots=(list [p=@da =timebox:store])
(tap:orm notifications)
|- =* outer $
?~ nots
+.state
?~ nots +.state
=/ unreads ~(tap by timebox.i.nots)
|- =* inner $
?~ unreads
@ -573,6 +651,6 @@
?: read.notification
inner(unreads t.unreads)
=. +.state
(upd-unreads index p.i.nots %.n)
(upd-cache %.n p.i.nots index)
inner(unreads t.unreads)
--

View File

@ -17,6 +17,15 @@
%+ scry-for update:store
/graph/(scot %p entity.res)/[name.res]
::
++ get-graph-mop
|= res=resource
^- graph:store
=/ =update:store
(get-graph res)
?> ?=(%0 -.update)
?> ?=(%add-graph -.q.update)
graph.q.update
::
++ gut-younger-node-siblings
|= [res=resource =index:store]
^- (map index:store node:store)

View File

@ -27,6 +27,17 @@
description+so
index+(su ;~(pfix fas (more fas dem)))
==
::
++ stats-index
%- of
:~ graph+graph-stats-index
group+dejs-path:resource
==
++ graph-stats-index
%- ot
:~ graph+dejs-path:resource
index+graph-store-index
==
:: parse date as @ud
:: TODO: move to zuse
++ sd
@ -41,6 +52,8 @@
:~ time+sd
index+index
==
++ graph-store-index
(su ;~(pfix fas (more fas dem)))
::
++ add
|= jon=json
@ -48,8 +61,8 @@
::
++ read-graph-index
%- ot
:~ index+index
target+(su ;~(pfix fas (more fas dem)))
:~ index+stats-index
target+graph-store-index
==
::
++ action
@ -61,7 +74,7 @@
read-note+notif-ref
add-note+add
set-dnd+bo
read-count+index
read-count+stats-index
read-each+read-graph-index
==
--
@ -81,25 +94,44 @@
%count (numb count.upd)
%more (more +.upd)
%read-each (read-each +.upd)
%read-count (index +.upd)
%read-count (stats-index +.upd)
%unread-each (unread-each +.upd)
%unread-count (unread-count +.upd)
%remove-graph s+(enjs-path:resource +.upd)
%seen-index (seen-index +.upd)
%unreads (unreads +.upd)
::
?(%archive %read-note %unread-note)
(notif-ref +.upd)
==
::
++ stats-index
|= s=^stats-index
%+ frond -.s
|^
?- -.s
%graph (graph-stats-index +.s)
%group s+(enjs-path:resource +.s)
==
::
++ graph-stats-index
|= [graph=resource =index:graph-store]
%- pairs
:~ graph+s+(enjs-path:resource graph)
index+(index:enjs:graph-store index)
==
--
::
++ unreads
|= l=(list [^index ^index-stats])
|= l=(list [^stats-index ^stats])
^- json
:- %a
^- (list json)
%+ turn l
|= [idx=^index stats=^index-stats]
|= [idx=^stats-index s=^stats]
%- pairs
:~ stats+(index-stats stats)
index+(index idx)
:~ stats+(stats s)
index+(stats-index idx)
==
::
++ unread
@ -113,13 +145,13 @@
(numb num.unreads)
==
::
++ index-stats
|= stats=^index-stats
++ stats
|= s=^stats
^- json
%- pairs
:~ unreads+(unread unreads.stats)
notifications+(numb notifications.stats)
last+(time last-seen.stats)
:~ unreads+(unread unreads.s)
notifications+(numb notifications.s)
last+(time last-seen.s)
==
++ added
|= [tim=@da idx=^index not=^notification]
@ -137,6 +169,13 @@
:~ time+s+(scot %ud tim)
index+(index idx)
==
++ seen-index
|= [tim=@da idx=^stats-index]
^- json
%- pairs
:~ time+(time tim)
index+(stats-index idx)
==
::
++ more
|= upds=(list ^update)
@ -236,26 +275,45 @@
==
::
++ read-each
|= [=^index target=index:graph-store]
|= [s=^stats-index target=index:graph-store]
%- pairs
:~ index+(^index index)
:~ index+(stats-index s)
target+(index:enjs:graph-store target)
==
::
++ unread-each
|= [=^index target=index:graph-store tim=@da]
|= [s=^stats-index target=index:graph-store tim=@da]
%- pairs
:~ index+(^index index)
:~ index+(stats-index s)
target+(index:enjs:graph-store target)
last+(time tim)
==
::
++ unread-count
|= [=^index tim=@da]
|= [s=^stats-index tim=@da]
%- pairs
:~ index+(^index index)
:~ index+(stats-index s)
last+(time tim)
==
--
--
::
++ to-stats-index
|= =index
^- stats-index
?- -.index
%graph [%graph graph.index index.index]
%group [%group group.index]
==
++ stats-index-is-index
|= [=stats-index =index]
?- -.index
%graph
?. ?=(%graph -.stats-index) %.n
=([graph index]:index [graph index]:stats-index)
::
%group
?. ?=(%group -.stats-index) %.n
=(group:index group:stats-index)
==
--

View File

@ -564,7 +564,12 @@
::
++ se-klin :: disconnect app
|= gyl=gill:gall
+>(eel (~(del in eel) gyl))
=/ gil=(unit gill:gall) se-agon
=. eel (~(del in eel) gyl)
?~ gil +>.$
?: =(gyl u.gil)
+>.$(inx 0)
(se-alas u.gil)
::
++ se-link :: connect to app
|= gyl=gill:gall
@ -788,6 +793,7 @@
?- fec
[%bel *] ta-bel
[%blk *] +>
[%bye *] +>(..ta (se-klin gyl))
[%clr *] +>(..ta (se-blit fec))
[%det *] (ta-got +.fec)
[%err *] (ta-err p.fec)

View File

@ -7,7 +7,7 @@
?+ index.p.i ~
[@ ~] `[%link 0 %each %.y]
[@ @ %1 ~] `[%comment 1 %count %.n]
[@ @ @ ~] `[%edit-comment 1 %count %.n]
[@ @ @ ~] `[%edit-comment 1 %none %.n]
==
--
++ grab

View File

@ -9,9 +9,9 @@
++ notification-kind
?+ index.p.i ~
[@ %1 %1 ~] `[%note 0 %each %.n]
[@ %1 @ ~] `[%edit-note 0 %each %.n]
[@ %1 @ ~] `[%edit-note 0 %none %.n]
[@ %2 @ %1 ~] `[%comment 1 %count %.n]
[@ %2 @ @ ~] `[%edit-comment 1 %count %.n]
[@ %2 @ @ ~] `[%edit-comment 1 %none %.n]
==
--
++ grab

View File

@ -75,7 +75,7 @@
info+(tape ~(ram re tank))
==
::
?(%bel %clr %nex)
?(%bel %clr %nex %bye)
(frond %act %s -.sef)
==
--

View File

@ -35,6 +35,20 @@
[date=@da read=? =contents]
--
::
++ state-one
|%
+$ state
$: %1
unreads-each=(jug index index:graph-store)
unreads-count=(map index @ud)
last-seen=(map index @da)
=notifications
archive=notifications
current-timebox=@da
dnd=_|
==
--
::
+$ index
$% $: %graph
group=resource
@ -70,24 +84,33 @@
$% [%add-note =index =notification]
[%archive time=@da index]
::
[%unread-count =index =time]
[%read-count =index]
[%unread-count =stats-index =time]
[%read-count =stats-index]
::
[%unread-each =index ref=index:graph-store time=@da]
[%read-each index ref=index:graph-store]
::
[%unread-each =stats-index ref=index:graph-store time=@da]
[%read-each =stats-index ref=index:graph-store]
::
[%read-note time=@da index]
[%unread-note time=@da index]
::
[%seen-index time=@da =stats-index]
[%remove-graph =resource]
::
[%read-all ~]
[%set-dnd dnd=?]
[%seen ~]
==
::
++ stats-index
$% [%graph graph=resource =index:graph-store]
[%group group=resource]
==
::
+$ indexed-notification
[index notification]
::
+$ index-stats
+$ stats
[notifications=@ud =unreads last-seen=@da]
::
+$ unreads
@ -99,10 +122,9 @@
$% action
[%more more=(list update)]
[%added time=@da =index =notification]
[%read-index =index]
[%read time=@da =index]
[%timebox time=@da archived=? =(list [index notification])]
[%count count=@ud]
[%unreads unreads=(list [index index-stats])]
[%clear =stats-index]
[%unreads unreads=(list [stats-index stats])]
==
--

View File

@ -30,6 +30,7 @@
+$ sole-effect :: app to sole
$% [%bel ~] :: beep
[%blk p=@ud q=@c] :: blink+match char at
[%bye ~] :: close session
[%clr ~] :: clear screen
[%det sole-change] :: edit command
[%err p=@ud] :: error point

File diff suppressed because it is too large Load Diff

View File

@ -121,7 +121,7 @@ export class Eyre extends Component {
</>);
const subscriptionItems = c.subscriptions.map(s => {
//NOTE jsx sorta copied from /components/subscriptions
return {key: `${s.id} ${s.app} ${s.ship} ${s.path}`, jsx: (
return {key: `${s.id} ${s.ship} ${s.app} ${s.path}`, jsx: (
<div class="flex">
<div class="flex-auto" style={{maxWidth: '15%'}}>
{s.id}
@ -144,7 +144,7 @@ export class Eyre extends Component {
return {key: c.session, jsx: (
<Summary summary={summary} details={(
<SearchableList
placeholder="id, app, ship, path"
placeholder="id, ship, app, path"
items={subscriptionItems}
/>
)} />

View File

@ -1693,9 +1693,9 @@
"integrity": "sha512-3OPSdf9cejP/TSzWXuBaYbzLtAfBzQnc75SlPLkoPfwpxnv1Bvy9hiWngLY0WnKRR6lMOldnkYQCCuNWeDibYQ=="
},
"@tlon/indigo-react": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/@tlon/indigo-react/-/indigo-react-1.2.5.tgz",
"integrity": "sha512-NOQTwH74l/XXMIfQ4ZzymvZuk1WK1nmO552TmXrQxBUSb7HmdlA8anG5oRrvnLJTkajLCY59McLkDca+lCcvwg==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@tlon/indigo-react/-/indigo-react-1.2.15.tgz",
"integrity": "sha512-h9umWEzYZwyb53ujWoCQCJQwY9RUuoDaf6189+0LH3C7y9fybJe6vzbW6g2cUVH8dXA2EZkedS5nriYR0IpQbw==",
"requires": {
"@reach/menu-button": "^0.10.5",
"react": "^16.13.1",

View File

@ -199,7 +199,7 @@ export class HarkApi extends BaseApi<StoreState> {
getMore(archive = false) {
const offset = this.store.state[
archive ? 'archivedNotifications' : 'notifications'
].size;
]?.size || 0;
const count = 3;
return this.getSubset(offset,count, archive);
}

View File

@ -128,6 +128,7 @@ function graphWatchSelf(json: any, state: HarkState) {
}
function reduce(data: any, state: HarkState) {
console.log(data);
unread(data, state);
read(data, state);
archive(data, state);
@ -140,6 +141,22 @@ function reduce(data: any, state: HarkState) {
readSince(data, state);
unreadSince(data, state);
unreadEach(data, state);
seenIndex(data, state);
removeGraph(data, state);
}
function removeGraph(json: any, state: HarkState) {
const data = _.get(json, 'remove-graph');
if(data) {
delete state.unreads.graph[data];
}
}
function seenIndex(json: any, state: HarkState) {
const data = _.get(json, 'seen-index');
if(data) {
updateNotificationStats(state, data.index, 'last', () => data.time);
}
}
function readEach(json: any, state: HarkState) {
@ -152,16 +169,13 @@ function readEach(json: any, state: HarkState) {
function readSince(json: any, state: HarkState) {
const data = _.get(json, 'read-count');
if(data) {
console.log(data);
updateUnreadCount(state, data, () => 0)
}
}
function unreadSince(json: any, state: HarkState) {
const data = _.get(json, 'unread-count');
console.log(data);
if(data) {
updateNotificationStats(state, data.index, 'last', () => data.last)
updateUnreadCount(state, data.index, u => u + 1);
}
}
@ -169,7 +183,6 @@ function unreadSince(json: any, state: HarkState) {
function unreadEach(json: any, state: HarkState) {
const data = _.get(json, 'unread-each');
if(data) {
updateNotificationStats(state, data.index, 'last', () => data.last);
updateUnreads(state, data.index, us => us.add(data.target))
}
}
@ -199,7 +212,8 @@ function updateUnreadCount(state: HarkState, index: NotifIndex, count: (c: numbe
}
const property = [index.graph.graph, index.graph.index, 'unreads'];
const curr = _.get(state.unreads.graph, property, 0);
_.set(state.unreads.graph, property, count(curr));
const newCount = count(curr)
_.set(state.unreads.graph, property, newCount);
}
function updateUnreads(state: HarkState, index: NotifIndex, f: (us: Set<string>) => void) {
@ -207,7 +221,9 @@ function updateUnreads(state: HarkState, index: NotifIndex, f: (us: Set<string>)
return;
}
const unreads = _.get(state.unreads.graph, [index.graph.graph, index.graph.index, 'unreads'], new Set<string>());
const oldSize = unreads.size;
f(unreads);
const newSize = unreads.size;
_.set(state.unreads.graph, [index.graph.graph, index.graph.index, 'unreads'], unreads);
}
@ -222,9 +238,6 @@ function updateNotificationStats(state: HarkState, index: NotifIndex, statField:
} else if('group' in index) {
const curr = _.get(state.unreads.group, [index.group.group, statField], 0);
_.set(state.unreads.group, [index.group.group, statField], f(curr));
} else if('chat' in index) {
const curr = _.get(state.unreads.chat, [index.chat.chat, statField], 0);
_.set(state.unreads.chat, [index.chat.chat, statField], f(curr));
}
}
@ -350,11 +363,6 @@ function archive(json: any, state: HarkState) {
notifIdxEqual(index, idxNotif.index)
);
state.notifications.set(time, unarchived);
const archiveBox = state.archivedNotifications.get(time) || [];
const readCount = archived.filter(
({ notification }) => !notification.read
).length;
updateNotificationStats(state, index, 'notifications', x => x - readCount);
state.archivedNotifications.set(time, [
...archiveBox,
...archived.map(({ notification, index }) => ({

View File

@ -76,7 +76,6 @@ export const LinkItem = (props: LinkItemProps) => {
const markRead = () => {
api.hark.markEachAsRead(props.association, '/', `/${index}`, 'link', 'link');
console.log('mark read');
}
return (
<Box width="100%" {...rest}>

View File

@ -45,12 +45,14 @@ export function Note(props: NoteProps & RouteComponentProps) {
const comments = getComments(note);
const [revNum, title, body, post] = getLatestRevision(note);
const index = note.post.index.split('/');
const noteId = bigInt(index[1]);
useEffect(() => {
api.hark.markEachAsRead(props.association, '/', post.index, 'note', 'publish');
api.hark.markEachAsRead(props.association, '/',`/${index[1]}/1/1`, 'note', 'publish');
}, [props.association]);
const noteId = bigInt(note.post.index.split('/')[1]);
let adminLinks: JSX.Element | null = null;
if (window.ship === note?.post?.author) {

View File

@ -45,7 +45,7 @@ export function NotePreview(props: NotePreviewProps) {
const [rev, title, body, content] = getLatestRevision(node);
const appPath = `/ship/${props.host}/${props.book}`;
const isUnread = props.unreads.graph?.[appPath]?.['/']?.unreads?.has(content.index);
const isUnread = props.unreads.graph?.[appPath]?.['/']?.unreads?.has(`/${noteId}/1/1`);
const snippet = getSnippet(body);