From 751f3d1f24b79659447cceba51cbaba696c9c5c4 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 16 Apr 2021 12:58:27 -0500 Subject: [PATCH 01/58] server: fix session js caching, add cache threading for other response types, switch from tape to cord interpolation --- pkg/arvo/app/file-server.hoon | 7 ++-- pkg/arvo/lib/server.hoon | 65 ++++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/pkg/arvo/app/file-server.hoon b/pkg/arvo/app/file-server.hoon index 8bff63cc79..1cdff8bbac 100644 --- a/pkg/arvo/app/file-server.hoon +++ b/pkg/arvo/app/file-server.hoon @@ -188,8 +188,11 @@ ?: ?=([%'~landscape' %js %session ~] site.req-line) %+ require-authorization-simple:app inbound-request - %- js-response:gen - (as-octt:mimes:html "window.ship = '{+:(scow %p our.bowl)}';") + %. %- as-octs:mimes:html + :((cury cat 3) 'window.ship = "' (rsh 3 (scot %p our.bowl)) '";') + %* . js-response:gen + cache %.n + == :: =/ [payload=simple-payload:http public=?] (get-file req-line is-file) ?: public payload diff --git a/pkg/arvo/lib/server.hoon b/pkg/arvo/lib/server.hoon index 1f450c3e50..2bb6f55212 100644 --- a/pkg/arvo/lib/server.hoon +++ b/pkg/arvo/lib/server.hoon @@ -39,10 +39,10 @@ ~! +:*handler (handler inbound-request) :: - =/ redirect=cord - %- crip - "/~/login?redirect={(trip url.request.inbound-request)}" - [[307 ['location' redirect]~] ~] + =- [[307 ['location' -]~] ~] + %^ cat 3 + '/~/login?redirect=' + url.request.inbound-request :: :: +require-authorization-simple: :: redirect to the login page when unauthenticated @@ -56,10 +56,10 @@ ~! this simple-payload :: - =/ redirect=cord - %- crip - "/~/login?redirect={(trip url.request.inbound-request)}" - [[307 ['location' redirect]~] ~] + =- [[307 ['location' -]~] ~] + %^ cat 3 + '/~/login?redirect=' + url.request.inbound-request :: ++ give-simple-payload |= [eyre-id=@ta =simple-payload:http] @@ -86,36 +86,47 @@ :_ `octs [200 [['content-type' 'text/html'] ?:(cache [max-1-wk ~] ~)]] :: - ++ js-response - |= =octs - ^- simple-payload:http - [[200 [['content-type' 'text/javascript'] max-1-da ~]] `octs] - :: - ++ json-response - |= =json - ^- simple-payload:http - [[200 ['content-type' 'application/json']~] `(json-to-octs json)] - :: ++ css-response + =| cache=? |= =octs ^- simple-payload:http - [[200 [['content-type' 'text/css'] max-1-da ~]] `octs] + :_ `octs + [200 [['content-type' 'text/css'] ?:(cache [max-1-wk ~] ~)]] :: - ++ manx-response - |= man=manx + ++ js-response + =| cache=? + |= =octs ^- simple-payload:http - [[200 ['content-type' 'text/html']~] `(manx-to-octs man)] + :_ `octs + [200 [['content-type' 'text/javascript'] ?:(cache [max-1-wk ~] ~)]] :: ++ png-response + =| cache=? |= =octs ^- simple-payload:http - [[200 [['content-type' 'image/png'] max-1-wk ~]] `octs] + :_ `octs + [200 [['content-type' 'image/png'] ?:(cache [max-1-wk ~] ~)]] :: ++ woff2-response + =| cache=? |= =octs ^- simple-payload:http [[200 [['content-type' 'font/woff2'] max-1-wk ~]] `octs] :: + ++ json-response + =| cache=_| + |= =json + ^- simple-payload:http + :_ `(json-to-octs json) + [200 [['content-type' 'application/json'] ?:(cache [max-1-da ~] ~)]] + :: + ++ manx-response + =| cache=_| + |= man=manx + ^- simple-payload:http + :_ `(manx-to-octs man) + [200 [['content-type' 'text/html'] ?:(cache [max-1-da ~] ~)]] + :: ++ not-found ^- simple-payload:http [[404 ~] ~] @@ -123,10 +134,10 @@ ++ login-redirect |= =request:http ^- simple-payload:http - =/ redirect=cord - %- crip - "/~/login?redirect={(trip url.request)}" - [[307 ['location' redirect]~] ~] + =- [[307 ['location' -]~] ~] + %^ cat 3 + '/~/login?redirect=' + url.request :: ++ redirect |= redirect=cord From 3c8117db72ed515422e6f831a877bf47cb363815 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 16 Apr 2021 13:01:27 -0500 Subject: [PATCH 02/58] file-server: since %glob hash changes per commit, cache for 1wk instead of 1da --- pkg/arvo/app/file-server.hoon | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/arvo/app/file-server.hoon b/pkg/arvo/app/file-server.hoon index 1cdff8bbac..771d054a6d 100644 --- a/pkg/arvo/app/file-server.hoon +++ b/pkg/arvo/app/file-server.hoon @@ -241,11 +241,9 @@ [not-found:gen %.n] :_ public.u.content =/ mime-type=@t (rsh 3 (crip )) - :: Should maybe inspect to see how long cache should hold - :: =/ headers :~ content-type+mime-type - max-1-da:gen + max-1-wk:gen 'service-worker-allowed'^'/' == [[200 headers] `q.u.data] From 050133338de5f5800ef9cb4777624a5adbb65d62 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 16 Apr 2021 16:45:22 -0500 Subject: [PATCH 03/58] file-server: use rap 3 instead of cury cat 3 --- pkg/arvo/app/file-server.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/app/file-server.hoon b/pkg/arvo/app/file-server.hoon index 771d054a6d..08461e5cb1 100644 --- a/pkg/arvo/app/file-server.hoon +++ b/pkg/arvo/app/file-server.hoon @@ -189,7 +189,7 @@ %+ require-authorization-simple:app inbound-request %. %- as-octs:mimes:html - :((cury cat 3) 'window.ship = "' (rsh 3 (scot %p our.bowl)) '";') + (rap 3 'window.ship = "' (rsh 3 (scot %p our.bowl)) '";' ~) %* . js-response:gen cache %.n == From 2ab7fbd08fa6bbb8827387c152201537420b45c9 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 19 Apr 2021 23:00:02 +0200 Subject: [PATCH 04/58] acme: don't no-op for moons and comets --- pkg/arvo/app/acme.hoon | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/arvo/app/acme.hoon b/pkg/arvo/app/acme.hoon index bbb53b8eb4..7d64a69f3f 100644 --- a/pkg/arvo/app/acme.hoon +++ b/pkg/arvo/app/acme.hoon @@ -1394,8 +1394,6 @@ ^+ this ?: =(~ dom) ~|(%acme-empty-certificate-order !!) - ?: ?=(?(%earl %pawn) (clan:title our.bow)) - this =. ..emit (queue-next-order 1 | dom) =. ..emit cancel-current-order :: notify %dill From c8565e2c3b66b33aa2effee4e4de0614078f832c Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 20 Apr 2021 15:58:12 -0500 Subject: [PATCH 05/58] graph-store lib: skip trip and crip, use rap --- pkg/arvo/lib/graph-store.hoon | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/pkg/arvo/lib/graph-store.hoon b/pkg/arvo/lib/graph-store.hoon index 1dd12e82a3..c19282aa5b 100644 --- a/pkg/arvo/lib/graph-store.hoon +++ b/pkg/arvo/lib/graph-store.hoon @@ -145,18 +145,17 @@ == :: ++ index - |= i=^index + |= ind=^index ^- json - ?: =(~ i) s+'/' - =/ j=^tape "" - |- - ?~ i [%s (crip j)] - =/ k=json (numb i.i) - ?> ?=(%n -.k) - %_ $ - i t.i - j (weld j (weld "/" (trip +.k))) - == + :- %s + ?: =(~ ind) + '/' + %+ roll ind + |= [cur=@ acc=@t] + ^- @t + =/ num (numb cur) + ?> ?=(%n -.num) + (rap 3 acc '/' p.num ~) :: ++ uid |= u=^uid From cd627d452c24201a7c4bce90a90cce09acce7048 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 20 Apr 2021 16:25:43 -0500 Subject: [PATCH 06/58] metadata-store lib: replace crip, trip with rap 3 --- pkg/arvo/lib/metadata-store.hoon | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/arvo/lib/metadata-store.hoon b/pkg/arvo/lib/metadata-store.hoon index 23a6878f97..304c988c57 100644 --- a/pkg/arvo/lib/metadata-store.hoon +++ b/pkg/arvo/lib/metadata-store.hoon @@ -23,13 +23,13 @@ %+ turn ~(tap by associations) |= [=md-resource [group=resource =^metadatum]] ^- [cord json] - :- - %- crip - ;: weld - (trip (spat (en-path:resource group))) - (weld "/" (trip app-name.md-resource)) - (trip (spat (en-path:resource resource.md-resource))) - == + :- %: rap 3 + (spat (en-path:resource group)) + '/' + app-name.md-resource + (spat (en-path:resource resource.md-resource)) + ~ + == %- pairs :~ [%group s+(enjs-path:resource group)] [%app-name s+app-name.md-resource] From b553b9534cb9e702333bac52c7792f97d0884af6 Mon Sep 17 00:00:00 2001 From: fang Date: Sat, 24 Apr 2021 21:03:48 +0200 Subject: [PATCH 07/58] chat-cli: update audience on-;view This feels more correct, and matches historic on-;join behavior. Fixes #4758. --- pkg/arvo/app/chat-cli.hoon | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/arvo/app/chat-cli.hoon b/pkg/arvo/app/chat-cli.hoon index b297103502..814e0b7516 100644 --- a/pkg/arvo/app/chat-cli.hoon +++ b/pkg/arvo/app/chat-cli.hoon @@ -734,7 +734,8 @@ :: ?. (is-chat-graph target) [[(note:sh-out "no such chat")]~ put-ses] - =. viewing (~(put in viewing) target) + =. audience target + =. viewing (~(put in viewing) target) =^ cards state ?: (~(has by bound) target) [~ state] From 04537e6fc1db0fbe9d74ffdd4c3cab4d4e753007 Mon Sep 17 00:00:00 2001 From: rabsef-bicrym Date: Thu, 29 Apr 2021 04:38:43 +0000 Subject: [PATCH 08/58] Added support for .ico files: -/mar/ico/hoon * Utilizes similar structure to /mar/png/hoon, w/ changed mimetype -/lib/server * Added ico-response, again similar to png w/ same caching -/app/file-server * Added reference to ico-response:gen i showed you my ico, plz respond --- pkg/arvo/app/file-server.hoon | 1 + pkg/arvo/lib/server.hoon | 5 +++++ pkg/arvo/mar/ico.hoon | 12 ++++++++++++ 3 files changed, 18 insertions(+) create mode 100644 pkg/arvo/mar/ico.hoon diff --git a/pkg/arvo/app/file-server.hoon b/pkg/arvo/app/file-server.hoon index 8bff63cc79..0c8db457cb 100644 --- a/pkg/arvo/app/file-server.hoon +++ b/pkg/arvo/app/file-server.hoon @@ -222,6 +222,7 @@ [~ %js] (js-response:gen file) [~ %css] (css-response:gen file) [~ %png] (png-response:gen file) + [~ %ico] (ico-response:gen file) :: [~ %html] %. file diff --git a/pkg/arvo/lib/server.hoon b/pkg/arvo/lib/server.hoon index 1f450c3e50..c0e29b79b4 100644 --- a/pkg/arvo/lib/server.hoon +++ b/pkg/arvo/lib/server.hoon @@ -110,6 +110,11 @@ |= =octs ^- simple-payload:http [[200 [['content-type' 'image/png'] max-1-wk ~]] `octs] + :: + ++ ico-response + |= =octs + ^- simple-payload:http + [[200 [['content-type' 'image/x-icon'] max-1-wk ~]] `octs] :: ++ woff2-response |= =octs diff --git a/pkg/arvo/mar/ico.hoon b/pkg/arvo/mar/ico.hoon new file mode 100644 index 0000000000..e862b9b9a9 --- /dev/null +++ b/pkg/arvo/mar/ico.hoon @@ -0,0 +1,12 @@ +|_ dat=@ +++ grow + |% + ++ mime [/image/x-icon (as-octs:mimes:html dat)] + -- +++ grab + |% + ++ mime |=([p=mite q=octs] q.q) + ++ noun @ + -- +++ grad %mime +-- From 4772b261addafe42e27a079185b01765b25bfcdc Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 25 Nov 2020 14:46:05 +0100 Subject: [PATCH 09/58] launch: expose runtime lag scry endpoint --- pkg/arvo/app/launch.hoon | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pkg/arvo/app/launch.hoon b/pkg/arvo/app/launch.hoon index 16997bfc0b..04df68453d 100644 --- a/pkg/arvo/app/launch.hoon +++ b/pkg/arvo/app/launch.hoon @@ -191,9 +191,14 @@ ^- (unit (unit cage)) ?. (team:title our.bowl src.bowl) ~ ?+ path [~ ~] - [%x %tiles ~] ``noun+!>([tiles tile-ordering]) - [%x %first-time ~] ``noun+!>(first-time) - [%x %keys ~] ``noun+!>(~(key by tiles)) + [%x %tiles ~] ``noun+!>([tiles tile-ordering]) + [%x %first-time ~] ``noun+!>(first-time) + [%x %keys ~] ``noun+!>(~(key by tiles)) + :: + [%x %runtime-lag ~] + :^ ~ ~ %json + !> ^- json + b+.^(? //(scot %p our.bowl)//(scot %da now.bowl)/zen/lag) == :: ++ on-arvo From 3a6735203c8031c8cdfd2b19345a140cfa018e01 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 30 Apr 2021 23:15:16 +0200 Subject: [PATCH 10/58] landscape: display version mismatch notification If arvo indicates it needs a newer runtime to apply an upgrade, we now display a persistent notification on the notifications screen and turn the base hash background yellow. This also gives a yellow notification dot, but it's overridden by the blue one if there are regular notifications too. --- pkg/interface/src/logic/api/local.ts | 6 +++++ .../src/logic/reducers/launch-update.ts | 7 ++++++ pkg/interface/src/logic/state/launch.ts | 4 +++- pkg/interface/src/types/local-update.ts | 5 ++++ pkg/interface/src/views/App.js | 1 + pkg/interface/src/views/apps/launch/app.js | 7 ++++-- .../src/views/apps/notifications/inbox.tsx | 23 ++++++++++++++++++- .../src/views/components/StatusBar.js | 7 ++++++ .../views/components/leap/OmniboxResult.js | 16 ++++++++++++- 9 files changed, 71 insertions(+), 5 deletions(-) diff --git a/pkg/interface/src/logic/api/local.ts b/pkg/interface/src/logic/api/local.ts index 305ac71f89..fefc7e339a 100644 --- a/pkg/interface/src/logic/api/local.ts +++ b/pkg/interface/src/logic/api/local.ts @@ -8,6 +8,12 @@ export default class LocalApi extends BaseApi { }); } + getRuntimeLag() { + return this.scry('launch', '/runtime-lag').then((runtimeLag) => { + this.store.handleEvent({ data: { runtimeLag } }); + }); + } + dehydrate() { this.store.dehydrate(); } diff --git a/pkg/interface/src/logic/reducers/launch-update.ts b/pkg/interface/src/logic/reducers/launch-update.ts index 7dfe948e31..43718fffe7 100644 --- a/pkg/interface/src/logic/reducers/launch-update.ts +++ b/pkg/interface/src/logic/reducers/launch-update.ts @@ -38,6 +38,13 @@ export default class LaunchReducer { state.baseHash = baseHash; }) } + + const runtimeLag = _.get(json, 'runtimeLag', null); + if (runtimeLag !== null) { + useLaunchState.getState().set(state => { + state.runtimeLag = runtimeLag; + }); + } } } diff --git a/pkg/interface/src/logic/state/launch.ts b/pkg/interface/src/logic/state/launch.ts index 225c002944..24add92059 100644 --- a/pkg/interface/src/logic/state/launch.ts +++ b/pkg/interface/src/logic/state/launch.ts @@ -12,6 +12,7 @@ export interface LaunchState extends BaseState { weather: WeatherState | null | Record | boolean, userLocation: string | null; baseHash: string | null; + runtimeLag: boolean; }; const useLaunchState = createState('Launch', { @@ -20,7 +21,8 @@ const useLaunchState = createState('Launch', { tiles: {}, weather: null, userLocation: null, - baseHash: null + baseHash: null, + runtimeLag: false, }); diff --git a/pkg/interface/src/types/local-update.ts b/pkg/interface/src/types/local-update.ts index 9813729f37..d2308de2a1 100644 --- a/pkg/interface/src/types/local-update.ts +++ b/pkg/interface/src/types/local-update.ts @@ -13,6 +13,10 @@ interface LocalUpdateBaseHash { baseHash: string; } +interface LocalUpdateRuntimeLag { + runtimeLag: boolean; +} + interface LocalUpdateBackgroundConfig { backgroundConfig: BackgroundConfig; } @@ -51,6 +55,7 @@ export type BackgroundConfig = BackgroundConfigUrl | BackgroundConfigColor | und export type LocalUpdate = | LocalUpdateSetDark | LocalUpdateBaseHash +| LocalUpdateRuntimeLag | LocalUpdateBackgroundConfig | LocalUpdateHideAvatars | LocalUpdateHideNicknames diff --git a/pkg/interface/src/views/App.js b/pkg/interface/src/views/App.js index 9e14446a27..685aa102f4 100644 --- a/pkg/interface/src/views/App.js +++ b/pkg/interface/src/views/App.js @@ -106,6 +106,7 @@ class App extends React.Component { this.updateTheme(this.themeWatcher); }, 500); this.api.local.getBaseHash(); + this.api.local.getRuntimeLag(); //TODO consider polling periodically this.api.settings.getAll(); gcpManager.start(); Mousetrap.bindGlobal(['command+/', 'ctrl+/'], (e) => { diff --git a/pkg/interface/src/views/apps/launch/app.js b/pkg/interface/src/views/apps/launch/app.js index eb4701ed43..0d525be958 100644 --- a/pkg/interface/src/views/apps/launch/app.js +++ b/pkg/interface/src/views/apps/launch/app.js @@ -47,7 +47,7 @@ const tutSelector = f.pick(['tutorialProgress', 'nextTutStep', 'hideGroups']); export default function LaunchApp(props) { const { connection } = props; - const baseHash = useLaunchState(state => state.baseHash); + const { baseHash, runtimeLag } = useLaunchState(state => state); const [hashText, setHashText] = useState(baseHash); const [exitingTut, setExitingTut] = useState(false); const seen = useSettingsState(s => s?.tutorial?.seen) ?? true; @@ -82,7 +82,10 @@ export default function LaunchApp(props) { }, 2000); }} > - + {hashText || baseHash} diff --git a/pkg/interface/src/views/apps/notifications/inbox.tsx b/pkg/interface/src/views/apps/notifications/inbox.tsx index 1746376afc..28a840dca5 100644 --- a/pkg/interface/src/views/apps/notifications/inbox.tsx +++ b/pkg/interface/src/views/apps/notifications/inbox.tsx @@ -4,7 +4,15 @@ import _ from 'lodash'; import moment from 'moment'; import { BigInteger } from 'big-integer'; -import { Col, Center, Box, Text, LoadingSpinner } from '@tlon/indigo-react'; +import { + Col, + Center, + Box, + Text, + LoadingSpinner, + Icon +} from '@tlon/indigo-react'; + import { Associations, Notifications, @@ -23,6 +31,7 @@ import GlobalApi from '~/logic/api/global'; import { Notification } from './notification'; import { Invites } from './invites'; import { useLazyScroll } from '~/logic/lib/useLazyScroll'; +import useLaunchState from '~/logic/state/launch'; import useHarkState from '~/logic/state/hark'; import useInviteState from '~/logic/state/invite'; import useMetadataState from '~/logic/state/metadata'; @@ -65,6 +74,8 @@ export default function Inbox(props: { }; }, []); + const runtimeLag = useLaunchState(state => state.runtimeLag); + const ready = useHarkState( s => Object.keys(s.unreads.graph).length > 0 ); @@ -122,6 +133,16 @@ export default function Inbox(props: { return ( + + {runtimeLag && ( + + + + Update your binary to continue receiving updates. + + + )} + {[...notificationsByDayMap.keys()].sort().reverse().map((day, index) => { const timeboxes = notificationsByDayMap.get(day)!; diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index f2bc362db9..8ea9936e58 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -18,6 +18,7 @@ import { uxToHex } from '~/logic/lib/util'; import { ProfileStatus } from './ProfileStatus'; import { useTutorialModal } from './useTutorialModal'; +import useLaunchState from '~/logic/state/launch'; import useHarkState from '~/logic/state/hark'; import useInviteState from '~/logic/state/invite'; import useContactState from '~/logic/state/contact'; @@ -30,6 +31,7 @@ const localSel = selectLocalState(['toggleOmnibox']); const StatusBar = (props) => { const { api, ship } = props; const history = useHistory(); + const runtimeLag = useLaunchState(state => state.runtimeLag); const ourContact = useContactState((state) => state.contacts[`~${ship}`]); const notificationsCount = useHarkState((state) => state.notificationsCount); const doNotDisturb = useHarkState((state) => state.doNotDisturb); @@ -86,6 +88,11 @@ const StatusBar = (props) => { toggleOmnibox()}> + {!doNotDisturb && runtimeLag && ( + + + + )} {!doNotDisturb && (notificationsCount > 0 || invites.length > 0) && ( diff --git a/pkg/interface/src/views/components/leap/OmniboxResult.js b/pkg/interface/src/views/components/leap/OmniboxResult.js index 87cdc07684..451830aaa3 100644 --- a/pkg/interface/src/views/components/leap/OmniboxResult.js +++ b/pkg/interface/src/views/components/leap/OmniboxResult.js @@ -4,6 +4,7 @@ import defaultApps from '~/logic/lib/default-apps'; import Sigil from '~/logic/lib/sigil'; import { uxToHex, cite } from '~/logic/lib/util'; import withState from '~/logic/lib/withState'; +import useLaunchState from '~/logic/state/launch'; import useHarkState from '~/logic/state/hark'; import useContactState from '~/logic/state/contact'; import useInviteState from '~/logic/state/invite'; @@ -31,11 +32,13 @@ export class OmniboxResult extends Component { } } - getIcon(icon, selected, link, invites, notifications, text, color) { + getIcon(icon, selected, link, invites, notifications, lag, text, color) { const iconFill = this.state.hovered || selected === link ? 'white' : 'black'; const bulletFill = this.state.hovered || selected === link ? 'white' : 'blue'; + const lagFill = + this.state.hovered || selected === link ? 'white' : 'yellow'; const inviteCount = [].concat( ...Object.values(invites).map((obj) => Object.values(obj)) @@ -70,6 +73,14 @@ export class OmniboxResult extends Component { size='18px' color={iconFill} /> + {lag && ( + + )} {(notifications > 0 || inviteCount.length > 0) && ( Date: Thu, 6 May 2021 16:21:48 -0700 Subject: [PATCH 11/58] interface: adding basic notifications --- pkg/interface/src/logic/lib/util.ts | 19 +++++++++++++++ .../src/logic/reducers/hark-update.ts | 13 ++++++++--- pkg/interface/src/views/App.js | 23 ++----------------- .../components/lib/NotificationPref.tsx | 13 ++++++++++- 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/pkg/interface/src/logic/lib/util.ts b/pkg/interface/src/logic/lib/util.ts index 2b20c7047e..4c8748ec22 100644 --- a/pkg/interface/src/logic/lib/util.ts +++ b/pkg/interface/src/logic/lib/util.ts @@ -1,4 +1,5 @@ /* eslint-disable max-lines */ +import { sigil as sigiljs, stringRenderer } from '@tlon/sigil-js'; import { Association, Contact } from '@urbit/api'; import anyAscii from 'any-ascii'; import bigInt, { BigInteger } from 'big-integer'; @@ -6,7 +7,9 @@ import { enableMapSet } from 'immer'; import _ from 'lodash'; import f from 'lodash/fp'; import { useCallback, useEffect, useMemo, useState } from 'react'; +import { foregroundFromBackground } from '~/logic/lib/sigil'; import { IconRef } from '~/types'; +import useContactState from '../state/contact'; import useSettingsState from '../state/settings'; enableMapSet(); @@ -435,3 +438,19 @@ export function getItemTitle(association: Association): string { return association.metadata.title ?? association.resource ?? ''; } +export const favicon = () => { + let background = '#ffffff'; + const contacts = useContactState.getState().contacts; + if (contacts.hasOwnProperty(`~${window.ship}`)) { + background = `#${uxToHex(contacts[`~${window.ship}`].color)}`; + } + const foreground = foregroundFromBackground(background); + const svg = sigiljs({ + patp: window.ship, + renderer: stringRenderer, + size: 16, + colors: [background, foreground] + }); + const dataurl = 'data:image/svg+xml;base64,' + btoa(svg); + return dataurl; +} \ No newline at end of file diff --git a/pkg/interface/src/logic/reducers/hark-update.ts b/pkg/interface/src/logic/reducers/hark-update.ts index f40b9f2854..86fec6ea90 100644 --- a/pkg/interface/src/logic/reducers/hark-update.ts +++ b/pkg/interface/src/logic/reducers/hark-update.ts @@ -6,7 +6,7 @@ import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap'; import { BigInteger } from 'big-integer'; import _ from 'lodash'; import { compose } from 'lodash/fp'; -import { makePatDa } from '~/logic/lib/util'; +import { favicon, makePatDa } from '~/logic/lib/util'; import { reduceState } from '../state/base'; import useHarkState, { HarkState } from '../state/hark'; @@ -187,7 +187,14 @@ function readSince(json: any, state: HarkState): HarkState { function unreadSince(json: any, state: HarkState): HarkState { const data = _.get(json, 'unread-count'); - if(data) { + if (data) { + if (!useHarkState.getState().doNotDisturb && !document.hasFocus()) { + new Notification('New Landscape Notification', { + tag: 'landscape', + icon: favicon(), + image: favicon() + }); + } updateUnreadCount(state, data.index, u => u + 1); } return state; @@ -305,7 +312,7 @@ function removeNotificationFromUnread(state: HarkState, index: NotifIndex, time: } } -function updateNotificationStats(state: HarkState, index: NotifIndex, statField: 'unreads' | 'last', f: (x: number) => number) { +function updateNotificationStats(state: HarkState, index: NotifIndex, statField: 'unreads' | 'last', f: (x: number) => number, notify = false) { if('graph' in index) { const curr: any = _.get(state.unreads.graph, [index.graph.graph, index.graph.index, statField], 0); _.set(state.unreads.graph, [index.graph.graph, index.graph.index, statField], f(curr)); diff --git a/pkg/interface/src/views/App.js b/pkg/interface/src/views/App.js index b57bf8e055..0751906f60 100644 --- a/pkg/interface/src/views/App.js +++ b/pkg/interface/src/views/App.js @@ -1,6 +1,5 @@ import dark from '@tlon/indigo-dark'; import light from '@tlon/indigo-light'; -import { sigil as sigiljs, stringRenderer } from '@tlon/sigil-js'; import Mousetrap from 'mousetrap'; import 'mousetrap-global-bind'; import * as React from 'react'; @@ -11,8 +10,7 @@ import { BrowserRouter as Router, withRouter } from 'react-router-dom'; import styled, { ThemeProvider } from 'styled-components'; import GlobalApi from '~/logic/api/global'; import gcpManager from '~/logic/lib/gcpManager'; -import { foregroundFromBackground } from '~/logic/lib/sigil'; -import { uxToHex } from '~/logic/lib/util'; +import { favicon } from '~/logic/lib/util'; import withState from '~/logic/lib/withState'; import useContactState from '~/logic/state/contact'; import useGroupState from '~/logic/state/group'; @@ -86,7 +84,6 @@ class App extends React.Component { this.updateTheme = this.updateTheme.bind(this); this.updateMobile = this.updateMobile.bind(this); - this.faviconString = this.faviconString.bind(this); } componentDidMount() { @@ -129,22 +126,6 @@ class App extends React.Component { }); } - faviconString() { - let background = '#ffffff'; - if (this.props.contacts.hasOwnProperty(`~${window.ship}`)) { - background = `#${uxToHex(this.props.contacts[`~${window.ship}`].color)}`; - } - const foreground = foregroundFromBackground(background); - const svg = sigiljs({ - patp: window.ship, - renderer: stringRenderer, - size: 16, - colors: [background, foreground] - }); - const dataurl = 'data:image/svg+xml;base64,' + btoa(svg); - return dataurl; - } - getTheme() { const { props } = this; return ((props.dark && props?.display?.theme == 'auto') || @@ -161,7 +142,7 @@ class App extends React.Component { {window.ship.length < 14 - ? + ? : null} diff --git a/pkg/interface/src/views/apps/settings/components/lib/NotificationPref.tsx b/pkg/interface/src/views/apps/settings/components/lib/NotificationPref.tsx index abed89bb11..6e3b100426 100644 --- a/pkg/interface/src/views/apps/settings/components/lib/NotificationPref.tsx +++ b/pkg/interface/src/views/apps/settings/components/lib/NotificationPref.tsx @@ -1,11 +1,12 @@ import { + Button, Col, ManagedToggleSwitchField as Toggle, Text } from '@tlon/indigo-react'; import { Form, Formik, FormikHelpers } from 'formik'; import _ from 'lodash'; -import React, { useCallback } from 'react'; +import React, { useCallback, useState } from 'react'; import GlobalApi from '~/logic/api/global'; import { isWatching } from '~/logic/lib/hark'; import useHarkState from '~/logic/state/hark'; @@ -69,6 +70,8 @@ export function NotificationPreferences(props: { } }, [api, graphConfig, dnd]); + const [notificationsAllowed, setNotificationsAllowed] = useState(Notification.permission !== 'default'); + return ( <> @@ -85,6 +88,14 @@ export function NotificationPreferences(props: {
+ {notificationsAllowed + ? null + : + } Date: Thu, 6 May 2021 16:29:59 -0500 Subject: [PATCH 12/58] graph-push-hook: add better hints for profiling --- pkg/arvo/app/graph-push-hook.hoon | 46 +++++++++++++++++++++---------- pkg/arvo/lib/push-hook.hoon | 11 ++++++++ 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/pkg/arvo/app/graph-push-hook.hoon b/pkg/arvo/app/graph-push-hook.hoon index 62290f44d3..4f7eb6d10d 100644 --- a/pkg/arvo/app/graph-push-hook.hoon +++ b/pkg/arvo/app/graph-push-hook.hoon @@ -33,6 +33,7 @@ %- (agent:push-hook config) ^- agent =- +~% %graph-push-hook-agent ..scry.hook-core ~ =| state-one =* state - |_ =bowl:gall @@ -72,6 +73,7 @@ :: ++ on-fail on-fail:def ++ transform-proxy-update + ~/ %transform-proxy-update |= vas=vase ^- (unit vase) =/ =update:store !<(update:store vas) @@ -81,23 +83,31 @@ %add-nodes ?. (is-allowed-add:hc rid nodes.q.update) ~ + :: TODO: this scry is slow. =/ mark (get-mark:gra rid) ?~ mark `vas - |^ - =/ transform - !< $-([index:store post:store atom ?] [index:store post:store]) - %. !>(*indexed-post:store) - .^(tube:clay (scry:hc %cc %home /[u.mark]/transform-add-nodes)) - =/ [* result=(list [index:store node:store])] - %+ roll - (flatten-node-map ~(tap by nodes.q.update)) - (transform-list transform) - =. nodes.q.update - %- ~(gas by *(map index:store node:store)) - result - [~ !>(update)] + =< $ + ~% %transform-add-nodes ..transform-proxy-update ~ + |% + ++ $ + ^- (unit vase) + :: TODO: scries are slow, we should find a way to cache this so as + :: not to need to fetch it continually in the hot path + =/ transform + !< $-([index:store post:store atom ?] [index:store post:store]) + %. !>(*indexed-post:store) + .^(tube:clay (scry:hc %cc %home /[u.mark]/transform-add-nodes)) + =/ [* result=(list [index:store node:store])] + %+ roll + (flatten-node-map ~(tap by nodes.q.update)) + (transform-list transform) + =. nodes.q.update + %- ~(gas by *(map index:store node:store)) + result + [~ !>(update)] :: ++ flatten-node-map + ~/ %flatten-node-map |= lis=(list [index:store node:store]) ^- (list [index:store node:store]) |^ @@ -129,6 +139,7 @@ -- :: ++ transform-list + ~/ %transform-list |= transform=$-([index:store post:store atom ?] [index:store post:store]) |= $: [=index:store =node:store] [indices=(set index:store) lis=(list [index:store node:store])] @@ -172,6 +183,7 @@ ++ resource-for-update resource-for-update:gra :: ++ initial-watch + ~/ %initial-watch |= [=path =resource:res] ^- vase |^ @@ -211,7 +223,8 @@ == -- :: -^| ^= hook-core +~% %graph-push-hook-helper ..card.hook-core ~ +^= hook-core |_ =bowl:gall +* grp ~(. group bowl) met ~(. mdl bowl) @@ -254,6 +267,8 @@ ++ get-roles-writers-variation |= =resource:res ^- (unit [is-admin=? writers=(set ship) vip=vip-metadata:metadata]) + :: TODO: doing three scries in a row on the hot path is slow + :: =/ assoc=(unit association:metadata) (peek-association:met %graph resource) ?~ assoc ~ @@ -276,6 +291,8 @@ ++ is-allowed-add |= [=resource:res nodes=(map index:store node:store)] ^- ? + :: TODO: extremely slow due to scries. This takes about ~30ms per + :: %add-nodes event. |^ %- (bond |.(%.n)) %+ biff (get-roles-writers-variation resource) @@ -291,6 +308,7 @@ %.n ?. =(author.p.post.node src.bowl) %.n + :: TODO: these scries are slow, find a way to persistently cache them =/ =permissions:store %^ add-mark resource vip (node-to-indexed-post node) diff --git a/pkg/arvo/lib/push-hook.hoon b/pkg/arvo/lib/push-hook.hoon index e57f370d8b..9144988c97 100644 --- a/pkg/arvo/lib/push-hook.hoon +++ b/pkg/arvo/lib/push-hook.hoon @@ -26,6 +26,7 @@ :: /- *push-hook /+ default-agent, resource, verb, versioning, agentio +~% %push-hook-top ..part ~ |% +$ card card:agent:gall :: @@ -84,6 +85,7 @@ %.n :: ++ push-hook + ~/ %push-hook |* =config $_ ^| |_ bowl:gall @@ -175,6 +177,7 @@ =* state - ^- agent:gall =< + ~% %push-agent-lib ..poke-hook-action ~ |_ =bowl:gall +* this . og ~(. push-hook bowl) @@ -267,6 +270,7 @@ !>(state) :: ++ on-poke + ~/ %on-poke |= [=mark =vase] ^- (quip card:agent:gall agent:gall) ?: =(mark %push-hook-action) @@ -283,6 +287,7 @@ [cards this] :: ++ on-watch + ~/ %on-watch |= =path ^- (quip card:agent:gall agent:gall) ?: ?=([%version ~] path) @@ -320,6 +325,7 @@ -- :: ++ on-agent + ~/ %on-agent |= [=wire =sign:agent:gall] ^- (quip card:agent:gall agent:gall) ?. ?=([%helper %push-hook @ *] wire) @@ -373,6 +379,7 @@ [%x %min-version ~] ``version+!>(version.config) == -- + ~% %push-helper-lib ..card ~ |_ =bowl:gall +* og ~(. push-hook bowl) ver ~(. versioning [bowl [update-mark version min-version]:config]) @@ -380,6 +387,7 @@ pass pass:io :: ++ poke-hook-action + ~/ %poke-hook-action |= =action ^- (quip card:agent:gall _state) |^ @@ -448,6 +456,7 @@ [%pass wire %agent [our.bowl store-name.config] %watch store-path.config] :: ++ push-updates + ~/ %push-updates |= =cage ^- (list card:agent:gall) %+ roll (resource-for-update q.cage) @@ -484,6 +493,7 @@ -- :: ++ forward-update + ~/ %forward-update |= =cage ^- (list card:agent:gall) =- lis @@ -532,6 +542,7 @@ (slav %ud i.extra) :: ++ resource-for-update + ~/ %resource-for-update |= =vase ^- (list resource) %~ tap in From 9dbade620781b88dc9729b29fca038cbfbfc4735 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 7 May 2021 12:20:01 -0500 Subject: [PATCH 13/58] graph-push-hook: added more jet hints --- pkg/arvo/app/graph-push-hook.hoon | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/arvo/app/graph-push-hook.hoon b/pkg/arvo/app/graph-push-hook.hoon index 4f7eb6d10d..74216ae9cb 100644 --- a/pkg/arvo/app/graph-push-hook.hoon +++ b/pkg/arvo/app/graph-push-hook.hoon @@ -265,6 +265,7 @@ reader.permissions :: ++ get-roles-writers-variation + ~/ %get-roles-writers-variation |= =resource:res ^- (unit [is-admin=? writers=(set ship) vip=vip-metadata:metadata]) :: TODO: doing three scries in a row on the hot path is slow @@ -289,6 +290,7 @@ [(snag (dec (lent index)) index) p.post.node] :: ++ is-allowed-add + ~/ %is-allowed-add |= [=resource:res nodes=(map index:store node:store)] ^- ? :: TODO: extremely slow due to scries. This takes about ~30ms per @@ -332,6 +334,7 @@ -- :: ++ is-allowed-remove + ~/ %is-allowed-remove |= [=resource:res indices=(set index:store)] ^- ? |^ From f4388dc60e84c880f96dccef5075823c326581fd Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 7 May 2021 14:08:47 -0500 Subject: [PATCH 14/58] graph-push-hook: speed up +transform-proxy-update by using persistent caching --- pkg/arvo/app/contact-push-hook.hoon | 3 +- pkg/arvo/app/graph-push-hook.hoon | 310 +++++++++++++++++++-------- pkg/arvo/app/group-push-hook.hoon | 3 +- pkg/arvo/app/metadata-push-hook.hoon | 3 +- pkg/arvo/lib/group.hoon | 16 +- pkg/arvo/lib/push-hook.hoon | 10 +- pkg/arvo/mar/gph-cache-action.hoon | 21 ++ 7 files changed, 267 insertions(+), 99 deletions(-) create mode 100644 pkg/arvo/mar/gph-cache-action.hoon diff --git a/pkg/arvo/app/contact-push-hook.hoon b/pkg/arvo/app/contact-push-hook.hoon index ed2d4660bd..bb8a1a5262 100644 --- a/pkg/arvo/app/contact-push-hook.hoon +++ b/pkg/arvo/app/contact-push-hook.hoon @@ -70,10 +70,11 @@ :: ++ transform-proxy-update |= vas=vase - ^- (unit vase) + ^- (quip card (unit vase)) :: TODO: should check if user is allowed to %add, %remove, %edit :: contact =/ =update:store !<(update:store vas) + :- ~ ?- -.update %initial ~ %add `vas diff --git a/pkg/arvo/app/graph-push-hook.hoon b/pkg/arvo/app/graph-push-hook.hoon index 74216ae9cb..04ff1777ad 100644 --- a/pkg/arvo/app/graph-push-hook.hoon +++ b/pkg/arvo/app/graph-push-hook.hoon @@ -1,6 +1,6 @@ /- *group, metadata=metadata-store /+ store=graph-store, mdl=metadata, res=resource, graph, group, default-agent, - dbug, verb, push-hook + dbug, verb, push-hook, agentio :: ~% %graph-push-hook-top ..part ~ |% @@ -25,6 +25,25 @@ $% state-zero state-one == +:: ++$ cache + $: graph-to-md=(map resource:res association:metadata) + graph-to-mark=(map resource:res (unit mark)) + perm-marks=(map [mark @tas] tube:clay) + transform-marks=(map mark tube:clay) + == +:: ++$ inflated-state + $: state-one + cache + == +:: ++$ cache-action + $% [%graph-to-md (pair resource:res association:metadata)] + [%graph-to-mark (pair resource:res (unit mark))] + [%perm-marks (pair (pair mark @tas) tube:clay)] + [%transform-marks (pair mark tube:clay)] + == -- :: %- agent:dbug @@ -34,7 +53,7 @@ ^- agent =- ~% %graph-push-hook-agent ..scry.hook-core ~ -=| state-one +=| inflated-state =* state - |_ =bowl:gall +* this . @@ -42,10 +61,11 @@ grp ~(. group bowl) gra ~(. graph bowl) met ~(. mdl bowl) - hc ~(. hook-core bowl) + hc ~(. hook-core bowl +.state) + io ~(. agentio bowl) :: ++ on-init on-init:def -++ on-save !>(state) +++ on-save !>(-.state) ++ on-load |= =vase =+ !<(old=versioned-state vase) @@ -54,9 +74,28 @@ =? old ?=(%0 -.old) [%1 ~] ?> ?=(%1 -.old) - `this(state old) + `this(-.state old, +.state *cache) +:: +++ on-poke + |= [=mark =vase] + ^- (quip card _this) + ?. =(mark %gph-cache-action) + [~ this] + =/ a=cache-action !<(cache-action vase) + =* c +.state + =* graph-to-md graph-to-md.c + =* graph-to-mark graph-to-mark.c + =* perm-marks perm-marks.c + =* transform-marks transform-marks.c + =. c + ?- -.a + %graph-to-md c(graph-to-md (~(put by graph-to-md) p.a q.a)) + %graph-to-mark c(graph-to-mark (~(put by graph-to-mark) p.a q.a)) + %perm-marks c(perm-marks (~(put by perm-marks) p.a q.a)) + %transform-marks c(transform-marks (~(put by transform-marks) p.a q.a)) + == + [~ this(+.state c)] :: -++ on-poke on-poke:def ++ on-agent on-agent:def ++ on-watch on-watch:def ++ on-leave on-leave:def @@ -75,28 +114,39 @@ ++ transform-proxy-update ~/ %transform-proxy-update |= vas=vase - ^- (unit vase) + ^- (quip card (unit vase)) =/ =update:store !<(update:store vas) =* rid resource.q.update =. p.update now.bowl ?- -.q.update %add-nodes - ?. (is-allowed-add:hc rid nodes.q.update) - ~ - :: TODO: this scry is slow. - =/ mark (get-mark:gra rid) - ?~ mark `vas + =| cards=(list card) + =^ allowed cards (is-allowed-add:hc rid nodes.q.update) + ?. allowed + [cards ~] + =/ mark-cached (~(has by graph-to-mark) rid) + =/ mark + ?: mark-cached + (~(got by graph-to-mark) rid) + (get-mark:gra rid) + ?~ mark + [cards `vas] =< $ ~% %transform-add-nodes ..transform-proxy-update ~ |% ++ $ - ^- (unit vase) + ^- (quip card (unit vase)) :: TODO: scries are slow, we should find a way to cache this so as :: not to need to fetch it continually in the hot path + =/ transform-cached (~(has by transform-marks) u.mark) + =/ =tube:clay + ?: transform-cached + (~(got by transform-marks) u.mark) + .^(tube:clay (scry:hc %cc %home /[u.mark]/transform-add-nodes)) =/ transform !< $-([index:store post:store atom ?] [index:store post:store]) %. !>(*indexed-post:store) - .^(tube:clay (scry:hc %cc %home /[u.mark]/transform-add-nodes)) + tube =/ [* result=(list [index:store node:store])] %+ roll (flatten-node-map ~(tap by nodes.q.update)) @@ -104,7 +154,21 @@ =. nodes.q.update %- ~(gas by *(map index:store node:store)) result - [~ !>(update)] + :_ [~ !>(update)] + %+ weld cards + %- zing + :~ ?: mark-cached ~ + :_ ~ + %+ poke-self:pass:io %gph-cache-action + !> ^- cache-action + [%graph-to-mark rid mark] + :: + ?: transform-cached ~ + :_ ~ + %+ poke-self:pass:io %gph-cache-action + !> ^- cache-action + [%transform-marks u.mark tube] + == :: ++ flatten-node-map ~/ %flatten-node-map @@ -162,22 +226,26 @@ -- :: %remove-posts - ?. (is-allowed-remove:hc resource.q.update indices.q.update) + =| cards=(list card) + =^ allowed cards + (is-allowed-remove:hc rid indices.q.update) + :- cards + ?. allowed ~ `vas :: - %add-graph ~ - %remove-graph ~ - %add-signatures ~ - %remove-signatures ~ - %archive-graph ~ - %unarchive-graph ~ - %add-tag ~ - %remove-tag ~ - %keys ~ - %tags ~ - %tag-queries ~ - %run-updates ~ + %add-graph [~ ~] + %remove-graph [~ ~] + %add-signatures [~ ~] + %remove-signatures [~ ~] + %archive-graph [~ ~] + %unarchive-graph [~ ~] + %add-tag [~ ~] + %remove-tag [~ ~] + %keys [~ ~] + %tags [~ ~] + %tag-queries [~ ~] + %run-updates [~ ~] == :: ++ resource-for-update resource-for-update:gra @@ -225,10 +293,11 @@ :: ~% %graph-push-hook-helper ..card.hook-core ~ ^= hook-core -|_ =bowl:gall +|_ [=bowl:gall =cache] +* grp ~(. group bowl) met ~(. mdl bowl) gra ~(. graph bowl) + io ~(. agentio bowl) :: ++ scry |= [care=@t desk=@t =path] @@ -238,14 +307,38 @@ :: ++ perm-mark |= [=resource:res perm=@t vip=vip-metadata:metadata =indexed-post:store] - ^- permissions:store + ^- [permissions:store (list card)] |^ - =- (check vip) - !< check=$-(vip-metadata:metadata permissions:store) - %. !>(indexed-post) - =/ mark (get-mark:gra resource) - ?~ mark |=(=vase !>([%no %no %no])) - .^(tube:clay (scry %cc %home /[u.mark]/(perm-mark-name perm))) + =/ mark-cached (~(has by graph-to-mark.cache) resource) + =/ mark + ?: mark-cached + (~(got by graph-to-mark.cache) resource) + (get-mark:gra resource) + ?~ mark + [[%no %no %no] ~] + =/ key [u.mark (perm-mark-name perm)] + =/ perms-cached (~(has by perm-marks.cache) key) + =/ =tube:clay + ?: perms-cached + (~(got by perm-marks.cache) key) + .^(tube:clay (scry %cc %home /[u.mark]/(perm-mark-name perm))) + =/ check + !< $-(vip-metadata:metadata permissions:store) + (tube !>(indexed-post)) + :- (check vip) + %- zing + :~ ?: mark-cached ~ + :_ ~ + %+ poke-self:pass:io %gph-cache-action + !> ^- cache-action + [%graph-to-mark resource mark] + :: + ?: perms-cached ~ + :_ ~ + %+ poke-self:pass:io %gph-cache-action + !> ^- cache-action + [%perm-marks [u.mark (perm-mark-name perm)] tube] + == :: ++ perm-mark-name |= perm=@t @@ -268,15 +361,23 @@ ~/ %get-roles-writers-variation |= =resource:res ^- (unit [is-admin=? writers=(set ship) vip=vip-metadata:metadata]) - :: TODO: doing three scries in a row on the hot path is slow - :: =/ assoc=(unit association:metadata) - (peek-association:met %graph resource) + ?: (~(has by graph-to-md.cache) resource) + (~(get by graph-to-md.cache) resource) + (peek-association:met %graph resource) ?~ assoc ~ + =. graph-to-md.cache + (~(put by graph-to-md.cache) resource u.assoc) + =/ group=(unit group:grp) + (scry-group:grp group.u.assoc) + ?~ group ~ =/ role=(unit (unit role-tag)) - (role-for-ship:grp group.u.assoc src.bowl) + (role-for-ship-with-group:grp u.group group.u.assoc src.bowl) =/ writers=(set ship) - (get-tagged-ships:grp group.u.assoc [%graph resource %writers]) + %^ get-tagged-ships-with-group:grp + u.group + group.u.assoc + [%graph resource %writers] ?~ role ~ =/ is-admin=? ?=(?([~ %admin] [~ %moderator]) u.role) @@ -292,41 +393,59 @@ ++ is-allowed-add ~/ %is-allowed-add |= [=resource:res nodes=(map index:store node:store)] - ^- ? + ^- [? (list card)] :: TODO: extremely slow due to scries. This takes about ~30ms per :: %add-nodes event. |^ - %- (bond |.(%.n)) + %- (bond |.([%.n ~])) %+ biff (get-roles-writers-variation resource) |= [is-admin=? writers=(set ship) vip=vip-metadata:metadata] - ^- (unit ?) + ^- (unit [? (list card)]) %- some - %+ levy ~(tap by nodes) - |= [=index:store =node:store] - =/ parent-index=index:store - (scag (dec (lent index)) index) - ?: (~(has by nodes) parent-index) %.y - ?: ?=(%| -.post.node) - %.n - ?. =(author.p.post.node src.bowl) - %.n - :: TODO: these scries are slow, find a way to persistently cache them - =/ =permissions:store - %^ add-mark resource vip - (node-to-indexed-post node) - =/ =permission-level:store - (get-permission permissions is-admin writers) - ?- permission-level - %yes %.y - %no %.n - :: - %self - =/ parent-node=node:store - (got-node:gra resource parent-index) - ?: ?=(%| -.post.parent-node) - %.n - =(author.p.post.parent-node src.bowl) - == + =/ a ~(tap by nodes) + =| cards=(list card) + |- ^- [? (list card)] + ?~ a [& cards] + =/ c (check i.a is-admin writers vip) + =. cards (weld cards +.c) + ?. -.c [| cards] + $(a t.a) + :: + ++ check + |= $: [=index:store =node:store] + is-admin=? + writers=(set ship) + vip=vip-metadata:metadata + == + ^- [? (list card)] + =/ parent-index=index:store + (scag (dec (lent index)) index) + ?: (~(has by nodes) parent-index) + [%.y ~] + ?: ?=(%| -.post.node) + [%.n ~] + ?. =(author.p.post.node src.bowl) + [%.n ~] + :: TODO: these scries are slow, find a way to persistently cache them + =/ added + %^ add-mark resource vip + (node-to-indexed-post node) + =* permissions -.added + =* cards +.added + =/ =permission-level:store + (get-permission permissions is-admin writers) + :_ cards + ?- permission-level + %yes %.y + %no %.n + :: + %self + =/ parent-node=node:store + (got-node:gra resource parent-index) + ?: ?=(%| -.post.parent-node) + %.n + =(author.p.post.parent-node src.bowl) + == :: ++ add-mark |= [=resource:res vip=vip-metadata:metadata =indexed-post:store] @@ -336,28 +455,41 @@ ++ is-allowed-remove ~/ %is-allowed-remove |= [=resource:res indices=(set index:store)] - ^- ? + ^- [? (list card)] |^ - %- (bond |.(%.n)) + %- (bond |.([%.n ~])) %+ biff (get-roles-writers-variation resource) |= [is-admin=? writers=(set ship) vip=vip-metadata:metadata] - %- some - %+ levy ~(tap by indices) - |= =index:store - ^- ? - =/ =node:store - (got-node:gra resource index) - ?: ?=(%| -.post.node) %.n - =/ =permissions:store - %^ remove-mark resource vip - (node-to-indexed-post node) - =/ =permission-level:store - (get-permission permissions is-admin writers) - ?- permission-level - %yes %.y - %no %.n - %self =(author.p.post.node src.bowl) - == + %- some + =/ a ~(tap by indices) + =| cards=(list card) + |- ^- [? (list card)] + ?~ a [& cards] + =/ c (check i.a is-admin writers vip) + =. cards (weld cards +.c) + ?. -.c [| cards] + $(a t.a) + :: + ++ check + |= [=index:store is-admin=? writers=(set ship) vip=vip-metadata:metadata] + ^- [? (list card)] + =/ =node:store + (got-node:gra resource index) + ?: ?=(%| -.post.node) + [%.n ~] + =/ removed + %^ remove-mark resource vip + (node-to-indexed-post node) + =* permissions -.removed + =* cards +.removed + =/ =permission-level:store + (get-permission permissions is-admin writers) + :_ cards + ?- permission-level + %yes %.y + %no %.n + %self =(author.p.post.node src.bowl) + == :: ++ remove-mark |= [=resource:res vip=vip-metadata:metadata =indexed-post:store] diff --git a/pkg/arvo/app/group-push-hook.hoon b/pkg/arvo/app/group-push-hook.hoon index e1a2fc2376..20decf8c3a 100644 --- a/pkg/arvo/app/group-push-hook.hoon +++ b/pkg/arvo/app/group-push-hook.hoon @@ -47,8 +47,9 @@ :: ++ transform-proxy-update |= vas=vase - ^- (unit vase) + ^- (quip card (unit vase)) =/ =update:store !<(update:store vas) + :- ~ ?: ?=(%initial -.update) ~ |^ diff --git a/pkg/arvo/app/metadata-push-hook.hoon b/pkg/arvo/app/metadata-push-hook.hoon index a7ffd37bde..65ca2e00a2 100644 --- a/pkg/arvo/app/metadata-push-hook.hoon +++ b/pkg/arvo/app/metadata-push-hook.hoon @@ -59,8 +59,9 @@ :: ++ transform-proxy-update |= vas=vase - ^- (unit vase) + ^- (quip card (unit vase)) =/ =update:store !<(update:store vas) + :- ~ ?. ?=(?(%add %remove) -.update) ~ =/ role=(unit (unit role-tag)) diff --git a/pkg/arvo/lib/group.hoon b/pkg/arvo/lib/group.hoon index 436bffdef5..2e1b613327 100644 --- a/pkg/arvo/lib/group.hoon +++ b/pkg/arvo/lib/group.hoon @@ -75,7 +75,12 @@ =/ grp=(unit group) (scry-group rid) ?~ grp ~ - =* group u.grp + (role-for-ship-with-group u.grp rid ship) +:: +++ role-for-ship-with-group + |= [grp=group rid=resource =ship] + ^- (unit (unit role-tag)) + =* group grp =* policy policy.group =* tags tags.group =/ admins=(set ^ship) @@ -106,8 +111,13 @@ ^- (set ship) =/ grp=(unit group) (scry-group rid) - ?~ grp ~ - (~(get ju tags.u.grp) tag) + ?~ grp ~ + (get-tagged-ships-with-group u.grp rid tag) +:: +++ get-tagged-ships-with-group + |= [grp=group rid=resource =tag] + ^- (set ship) + (~(get ju tags.grp) tag) :: ++ is-managed |= rid=resource diff --git a/pkg/arvo/lib/push-hook.hoon b/pkg/arvo/lib/push-hook.hoon index 9144988c97..c5fe6c3fc9 100644 --- a/pkg/arvo/lib/push-hook.hoon +++ b/pkg/arvo/lib/push-hook.hoon @@ -115,7 +115,7 @@ :: ++ transform-proxy-update |~ vase - *(unit vase) + *[(list card) (unit vase)] :: +initial-watch: produce initial state for a subscription :: :: .resource is the resource being subscribed to. @@ -506,17 +506,19 @@ resource+(en-path:resource rid) =/ =wire (make-wire path) =* ship entity.rid - =. tf-vas + =/ out=[lis=(list card:agent:gall) tf-vas=(unit vase)] ?. =(our.bowl ship) :: do not transform before forwarding :: - `vas + [~ `vas] :: use cached transform :: - ?^ tf-vas tf-vas + ?^ tf-vas [~ tf-vas] :: transform before poking store :: (transform-proxy-update:og vas) + =. tf-vas tf-vas.out + =. lis (weld lis lis.out) ~| "forwarding failed during transform. mark: {} resource: {}" ?> ?=(^ tf-vas) =/ =dock diff --git a/pkg/arvo/mar/gph-cache-action.hoon b/pkg/arvo/mar/gph-cache-action.hoon new file mode 100644 index 0000000000..2bf223839d --- /dev/null +++ b/pkg/arvo/mar/gph-cache-action.hoon @@ -0,0 +1,21 @@ +/- metadata=metadata-store, res=resource +|% ++$ cache-action + $% [%graph-to-md (pair resource:res association:metadata)] + [%graph-to-mark (pair resource:res (unit mark))] + [%perm-marks (pair (pair mark @tas) tube:clay)] + [%transform-marks (pair mark tube:clay)] + == +-- +:: +|_ act=cache-action +++ grad %noun +++ grow + |% + ++ noun act + -- +++ grab + |% + ++ noun cache-action + -- +-- From 1a3bbe4ec93f82cc6e4d7071c1363e488ba3075a Mon Sep 17 00:00:00 2001 From: Tyler Brown Cifu Shuster Date: Wed, 5 May 2021 21:20:34 -0700 Subject: [PATCH 15/58] interface: cleaning up typescript errors --- pkg/interface/src/logic/api/graph.ts | 5 +- pkg/interface/src/logic/lib/hark.ts | 3 +- pkg/interface/src/logic/lib/permalinks.ts | 5 +- pkg/interface/src/logic/lib/publish.ts | 4 +- pkg/interface/src/logic/lib/useModal.tsx | 10 +-- .../src/logic/lib/{util.ts => util.tsx} | 9 ++- pkg/interface/src/logic/lib/withState.tsx | 12 +-- .../src/logic/reducers/graph-update.ts | 7 +- .../src/logic/reducers/hark-update.ts | 12 ++- pkg/interface/src/logic/state/base.ts | 8 +- .../views/apps/chat/components/ChatEditor.tsx | 20 +++-- .../views/apps/chat/components/ChatInput.tsx | 2 +- .../apps/chat/components/ChatMessage.tsx | 76 +++++++++---------- .../views/apps/chat/components/ChatPane.tsx | 6 +- .../views/apps/chat/components/ChatWindow.tsx | 16 ++-- .../apps/chat/components/UnreadNotice.tsx | 10 +-- pkg/interface/src/views/apps/graph/App.tsx | 5 +- pkg/interface/src/views/apps/launch/App.tsx | 32 ++++---- .../views/apps/launch/components/Groups.tsx | 8 +- .../views/apps/launch/components/tiles.tsx | 6 +- .../apps/launch/components/tiles/basic.tsx | 2 +- .../apps/launch/components/tiles/clock.tsx | 37 ++++++++- .../apps/launch/components/tiles/custom.tsx | 2 +- .../apps/launch/components/tiles/tile.tsx | 17 ++++- .../apps/launch/components/tiles/weather.tsx | 53 +++++++------ .../src/views/apps/links/LinkWindow.tsx | 13 +++- .../views/apps/links/components/LinkItem.tsx | 25 +++--- .../src/views/apps/notifications/graph.tsx | 33 +++----- .../src/views/apps/notifications/group.tsx | 3 +- .../src/views/apps/notifications/header.tsx | 12 +-- .../src/views/apps/notifications/inbox.tsx | 16 ++-- .../src/views/apps/notifications/joining.tsx | 8 +- .../src/views/apps/notifications/metadata.tsx | 12 +-- .../views/apps/notifications/notification.tsx | 10 +-- .../apps/notifications/notifications.tsx | 12 +-- .../views/apps/permalinks/TranscludedNode.tsx | 42 +++++----- .../src/views/apps/permalinks/app.tsx | 4 +- .../src/views/apps/permalinks/embed.tsx | 22 +++--- .../src/views/apps/permalinks/graphIndex.tsx | 4 +- .../apps/profile/components/EditProfile.tsx | 22 +++--- .../views/apps/profile/components/Profile.tsx | 24 +++--- .../apps/profile/components/ViewProfile.tsx | 6 +- .../src/views/apps/profile/profile.tsx | 2 +- .../apps/publish/components/EditPost.tsx | 5 +- .../publish/components/MarkdownEditor.tsx | 9 +-- .../apps/publish/components/MarkdownField.tsx | 2 +- .../views/apps/publish/components/Note.tsx | 13 ++-- .../publish/components/NoteNavigation.tsx | 6 +- .../apps/publish/components/NotePreview.tsx | 12 +-- .../apps/publish/components/NoteRoutes.tsx | 3 +- .../apps/publish/components/Notebook.tsx | 4 +- .../views/apps/publish/components/Writers.tsx | 10 +-- .../settings/components/lib/BackButton.tsx | 2 +- .../components/lib/BackgroundPicker.tsx | 14 ++-- .../settings/components/lib/BucketList.tsx | 16 ++-- .../apps/settings/components/lib/CalmPref.tsx | 8 +- .../apps/settings/components/lib/Debug.tsx | 8 +- .../settings/components/lib/DisplayForm.tsx | 10 +-- .../components/lib/GroupChannelPicker.tsx | 16 ++-- .../settings/components/lib/LeapSettings.tsx | 16 ++-- .../components/lib/NotificationPref.tsx | 14 ++-- .../apps/settings/components/lib/S3Form.tsx | 18 ++--- .../apps/settings/components/lib/Security.tsx | 16 ++-- .../apps/settings/components/settings.tsx | 14 ++-- .../src/views/apps/settings/settings.tsx | 6 +- pkg/interface/src/views/apps/term/api.tsx | 5 +- pkg/interface/src/views/apps/term/app.tsx | 15 ++-- .../views/apps/term/components/history.tsx | 4 +- .../src/views/apps/term/components/input.tsx | 12 +-- .../src/views/apps/term/components/line.tsx | 2 +- pkg/interface/src/views/apps/term/store.tsx | 4 + .../src/views/apps/term/subscription.tsx | 8 +- pkg/interface/src/views/components/Author.tsx | 5 +- .../src/views/components/ChipInput.tsx | 40 +++++----- .../src/views/components/ColorInput.tsx | 14 ++-- .../src/views/components/CommentItem.tsx | 17 +++-- .../src/views/components/Comments.tsx | 4 +- .../src/views/components/Dropdown.tsx | 6 +- .../src/views/components/DropdownSearch.tsx | 18 ++--- pkg/interface/src/views/components/Error.tsx | 2 +- .../src/views/components/FormGroup.tsx | 10 +-- .../src/views/components/FormSubmit.tsx | 4 +- .../src/views/components/GroupLink.tsx | 11 +-- .../src/views/components/GroupSearch.tsx | 22 +++--- .../src/views/components/IconRadio.tsx | 14 ++-- .../src/views/components/ImageInput.tsx | 4 +- .../src/views/components/Invite/Group.tsx | 21 +++-- .../components/Invite/InviteSkeleton.tsx | 6 +- .../views/components/Invite/JoinSkeleton.tsx | 2 +- .../src/views/components/Loading.tsx | 2 +- .../src/views/components/MentionText.tsx | 2 +- .../src/views/components/OverlaySigil.tsx | 19 +++-- .../src/views/components/ProfileOverlay.tsx | 53 +++++++------ .../src/views/components/ReconnectButton.tsx | 4 +- .../src/views/components/RemoteContent.tsx | 13 ++-- .../src/views/components/RichText.tsx | 21 ++++- .../src/views/components/ShipSearch.tsx | 20 ++--- .../src/views/components/ShuffleFields.tsx | 12 +-- .../src/views/components/Spinner.tsx | 4 +- .../views/components/StatelessAsyncToggle.tsx | 2 +- .../src/views/components/StatusBar.tsx | 20 ++--- .../src/views/components/SubmitDragger.tsx | 10 +-- .../src/views/components/UnjoinedResource.tsx | 12 +-- .../src/views/components/VirtualScroller.tsx | 12 +-- .../src/views/components/leap/Omnibox.tsx | 16 ++-- .../views/components/leap/OmniboxInput.tsx | 6 +- .../views/components/leap/OmniboxResult.tsx | 24 +++--- .../ChannelPermissions.tsx | 22 +++--- .../ChannelPopoverRoutes/Details.tsx | 12 +-- .../ChannelPopoverRoutes/Notifications.tsx | 6 +- .../ChannelPopoverRoutes/Sidebar.tsx | 12 +-- .../components/ChannelPopoverRoutes/index.tsx | 38 +++++----- .../components/ChannelWritePerms.tsx | 6 +- .../landscape/components/DeleteGroup.tsx | 12 +-- .../components/Graph/GraphContent.tsx | 76 ++++++++----------- .../components/Graph/content/code.js | 18 ++--- .../components/Graph/content/text.js | 24 +++--- .../components/GroupSettings/Admin.tsx | 12 +-- .../components/GroupSettings/Channels.tsx | 16 ++-- .../components/GroupSettings/GroupFeed.tsx | 8 +- .../GroupSettings/GroupSettings.tsx | 6 +- .../components/GroupSettings/Personal.tsx | 12 +-- .../landscape/components/GroupSummary.tsx | 14 ++-- .../landscape/components/GroupSwitcher.tsx | 22 +++--- .../landscape/components/GroupifyForm.tsx | 2 +- .../components/Home/AddFeedBanner.tsx | 6 +- .../components/Home/EmptyGroupHome.tsx | 2 +- .../components/Home/EnableGroupFeed.tsx | 10 +-- .../components/Home/GroupFeedHeader.tsx | 16 ++-- .../landscape/components/Home/GroupHome.tsx | 8 +- .../components/Home/Post/GroupFeedPerms.tsx | 6 +- .../components/Home/Post/PostFeed.tsx | 24 +++++- .../components/Home/Post/PostInput.tsx | 16 ++-- .../Home/Post/PostItem/PostContent.tsx | 8 +- .../Home/Post/PostItem/PostHeader.tsx | 6 +- .../Home/Post/PostItem/PostItem.tsx | 65 ++++++++++------ .../components/Home/Post/PostReplies.tsx | 15 ++-- .../components/Home/Post/PostTimeline.tsx | 48 +++++++----- .../landscape/components/InvitePopover.tsx | 8 +- .../views/landscape/components/JoinGroup.tsx | 32 ++++---- .../landscape/components/MessageInvite.tsx | 17 +++-- .../landscape/components/MetadataIcon.tsx | 2 +- .../views/landscape/components/NewChannel.tsx | 27 +++---- .../views/landscape/components/NewGroup.tsx | 11 +-- .../landscape/components/Participants.tsx | 34 ++++----- .../landscape/components/PopoverRoutes.tsx | 8 +- .../landscape/components/ResourceSkeleton.tsx | 24 +++--- .../landscape/components/Sidebar/Sidebar.tsx | 4 +- .../components/Sidebar/SidebarItem.tsx | 4 +- .../components/Sidebar/SidebarListHeader.tsx | 14 ++-- .../landscape/components/SidebarItem.tsx | 6 +- .../landscape/components/TutorialModal.tsx | 34 ++++----- pkg/npm/api/hark/types.ts | 4 +- pkg/npm/api/metadata/types.ts | 6 +- 154 files changed, 1151 insertions(+), 993 deletions(-) rename pkg/interface/src/logic/lib/{util.ts => util.tsx} (97%) diff --git a/pkg/interface/src/logic/api/graph.ts b/pkg/interface/src/logic/api/graph.ts index 95ca69ac2f..12fffce3a7 100644 --- a/pkg/interface/src/logic/api/graph.ts +++ b/pkg/interface/src/logic/api/graph.ts @@ -1,4 +1,5 @@ import { Content, Enc, GraphNode, GroupPolicy, Path, Patp, Post, Resource } from '@urbit/api'; +import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap'; import _ from 'lodash'; import { decToUd, deSig, resourceAsPath, unixToDa } from '~/logic/lib/util'; import { makeResource, resourceFromPath } from '../lib/group'; @@ -9,7 +10,7 @@ export const createBlankNodeWithChildPost = ( parentIndex = '', childIndex = '', contents: Content[] -) => { +): GraphNode => { const date = unixToDa(Date.now()).toString(); const nodeIndex = parentIndex + '/' + date; @@ -35,7 +36,7 @@ export const createBlankNodeWithChildPost = ( hash: null, signatures: [] }, - children: childGraph + children: childGraph as BigIntOrderedMap }; }; diff --git a/pkg/interface/src/logic/lib/hark.ts b/pkg/interface/src/logic/lib/hark.ts index f410e88d31..a5fe5883ea 100644 --- a/pkg/interface/src/logic/lib/hark.ts +++ b/pkg/interface/src/logic/lib/hark.ts @@ -1,5 +1,6 @@ import { IndexedNotification, NotificationGraphConfig, Unreads } from '@urbit/api'; import bigInt, { BigInteger } from 'big-integer'; +import _ from 'lodash'; import f from 'lodash/fp'; export function getLastSeen( @@ -31,7 +32,7 @@ export function getNotificationCount( ): number { const unread = unreads.graph?.[path] || {}; return Object.keys(unread) - .map(index => unread[index]?.notifications?.length || 0) + .map(index => _.get(unread[index], 'notifications.length', 0)) .reduce(f.add, 0); } diff --git a/pkg/interface/src/logic/lib/permalinks.ts b/pkg/interface/src/logic/lib/permalinks.ts index c6e0905495..d225dc317b 100644 --- a/pkg/interface/src/logic/lib/permalinks.ts +++ b/pkg/interface/src/logic/lib/permalinks.ts @@ -20,12 +20,13 @@ function getPermalinkForAssociatedGroup(group: string) { type Permalink = GraphPermalink | GroupPermalink; -interface GroupPermalink { +export interface GroupPermalink { type: 'group'; group: string; link: string; } -interface GraphPermalink { + +export interface GraphPermalink { type: 'graph'; link: string; graph: string; diff --git a/pkg/interface/src/logic/lib/publish.ts b/pkg/interface/src/logic/lib/publish.ts index 487fcdfd3f..c6478bbd7a 100644 --- a/pkg/interface/src/logic/lib/publish.ts +++ b/pkg/interface/src/logic/lib/publish.ts @@ -1,4 +1,4 @@ -import { GraphNode, Post, TextContent } from '@urbit/api'; +import { Content, GraphNode, Post } from '@urbit/api'; import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap'; import bigInt, { BigInteger } from 'big-integer'; import { buntPost } from '~/logic/lib/post'; @@ -118,7 +118,7 @@ export function getComments(node: GraphNode): GraphNode { return comments; } -export function getSnippet(body: any) { +export function getSnippet(body: string | Content[]) { const firstContent = Object.values(body[0])[0]; const newlineIdx = firstContent.indexOf('\n', 2); const end = newlineIdx > -1 ? newlineIdx : firstContent.length; diff --git a/pkg/interface/src/logic/lib/useModal.tsx b/pkg/interface/src/logic/lib/useModal.tsx index 95adb05706..9edbf011ab 100644 --- a/pkg/interface/src/logic/lib/useModal.tsx +++ b/pkg/interface/src/logic/lib/useModal.tsx @@ -1,9 +1,9 @@ import { Box } from '@tlon/indigo-react'; import React, { - ReactNode, - useCallback, - useMemo, - useRef, useState + ReactNode, + useCallback, + useMemo, + useRef, useState } from 'react'; import { PropFunc } from '~/types'; import { ModalOverlay } from '~/views/components/ModalOverlay'; @@ -57,7 +57,7 @@ export function useModal(props: UseModalProps & PropFunc): UseModalR display="flex" alignItems="stretch" flexDirection="column" - spacing="2" + spacing={2} dismiss={dismiss} {...rest} > diff --git a/pkg/interface/src/logic/lib/util.ts b/pkg/interface/src/logic/lib/util.tsx similarity index 97% rename from pkg/interface/src/logic/lib/util.ts rename to pkg/interface/src/logic/lib/util.tsx index 2b20c7047e..9d5911c4b4 100644 --- a/pkg/interface/src/logic/lib/util.ts +++ b/pkg/interface/src/logic/lib/util.tsx @@ -5,7 +5,7 @@ import bigInt, { BigInteger } from 'big-integer'; import { enableMapSet } from 'immer'; import _ from 'lodash'; import f from 'lodash/fp'; -import { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { IconRef } from '~/types'; import useSettingsState from '../state/settings'; @@ -423,6 +423,13 @@ export const useHovering = (): useHoveringInterface => { return useMemo(() => ({ hovering, bind }), [hovering, bind]); }; +export function withHovering(Component: React.ComponentType) { + const { hovering, bind } = useHovering(); + return (props: T) => ( + + ) +} + const DM_REGEX = /ship\/~([a-z]|-)*\/dm--/; export function getItemTitle(association: Association): string { if (DM_REGEX.test(association.resource)) { diff --git a/pkg/interface/src/logic/lib/withState.tsx b/pkg/interface/src/logic/lib/withState.tsx index 1ccd661468..80fdce4c15 100644 --- a/pkg/interface/src/logic/lib/withState.tsx +++ b/pkg/interface/src/logic/lib/withState.tsx @@ -19,12 +19,14 @@ const withStateo = < }); }; -const withState = < - StateType extends BaseState, - stateKey extends keyof StateType - >( +interface StatePicker extends Array { + 0: UseStore; + 1?: string[]; +} + +const withState = ( Component: any, - stores: ([UseStore, stateKey[]])[] + stores: StatePicker[] ) => { return React.forwardRef((props, ref) => { const stateProps: unknown = {}; diff --git a/pkg/interface/src/logic/reducers/graph-update.ts b/pkg/interface/src/logic/reducers/graph-update.ts index 1bb7632787..b049119131 100644 --- a/pkg/interface/src/logic/reducers/graph-update.ts +++ b/pkg/interface/src/logic/reducers/graph-update.ts @@ -1,3 +1,4 @@ +import { GraphNode } from '@urbit/api'; import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap'; import bigInt, { BigInteger } from 'big-integer'; import produce from 'immer'; @@ -52,14 +53,14 @@ const keys = (json, state: GraphState): GraphState => { const processNode = (node) => { // is empty if (!node.children) { - return produce(node, (draft) => { + return produce(node, (draft: GraphNode) => { draft.children = new BigIntOrderedMap(); }); } // is graph - return produce(node, (draft) => { - draft.children = new BigIntOrderedMap() + return produce(node, (draft: GraphNode) => { + draft.children = new BigIntOrderedMap() .gas(_.map(draft.children, (item, idx) => [bigInt(idx), processNode(item)] as [BigInteger, any] )); diff --git a/pkg/interface/src/logic/reducers/hark-update.ts b/pkg/interface/src/logic/reducers/hark-update.ts index f40b9f2854..50978b4e3a 100644 --- a/pkg/interface/src/logic/reducers/hark-update.ts +++ b/pkg/interface/src/logic/reducers/hark-update.ts @@ -64,11 +64,19 @@ function calculateCount(json: any, state: HarkState) { let count = 0; _.forEach(state.unreads.graph, (graphs) => { _.forEach(graphs, (graph) => { - count += (graph?.notifications || []).length; + if (typeof graph?.notifications === 'object') { + count += graph?.notifications.length; + } else { + count += 0; + } }); }); _.forEach(state.unreads.group, (group) => { - count += (group?.notifications || []).length; + if (typeof group?.notifications === 'object') { + count += group?.notifications.length; + } else { + count += 0; + } }); state.notificationsCount = count; return state; diff --git a/pkg/interface/src/logic/state/base.ts b/pkg/interface/src/logic/state/base.ts index 4286d2dcd1..c987df77a7 100644 --- a/pkg/interface/src/logic/state/base.ts +++ b/pkg/interface/src/logic/state/base.ts @@ -44,13 +44,13 @@ export interface BaseState extends State { set: (fn: (state: StateType) => void) => void; } -export const createState = ( +export const createState = >( name: string, - properties: T, + properties: { [K in keyof Omit]: T[K] }, blacklist: string[] = [] -): UseStore> => create(persist((set, get) => ({ +): UseStore => create(persist((set, get) => ({ set: fn => stateSetter(fn, set), - ...properties + ...properties as any }), { blacklist, name: stateStorageKey(name), diff --git a/pkg/interface/src/views/apps/chat/components/ChatEditor.tsx b/pkg/interface/src/views/apps/chat/components/ChatEditor.tsx index 3a805fc439..2f7a0b99d6 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatEditor.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatEditor.tsx @@ -108,8 +108,18 @@ interface ChatEditorState { message: string; } +interface CodeMirrorShim { + setValue: (string) => void; + setOption: (option: string, property: any) => void; + focus: () => void; + execCommand: (string) => void; + getValue: () => string; + getInputField: () => HTMLInputElement; + element: HTMLElement; +} + export default class ChatEditor extends Component { - editor: ProxyHandler | null; + editor: CodeMirrorShim; constructor(props: ChatEditorProps) { super(props); @@ -222,7 +232,7 @@ export default class ChatEditor extends Component { if (this.editor) { @@ -245,7 +255,7 @@ export default class ChatEditor extends Component - this.messageChange(null, null, event.target.value) + this.messageChange(null, null, (event.target as any).value) } ref={(input) => { if (!input) diff --git a/pkg/interface/src/views/apps/chat/components/ChatInput.tsx b/pkg/interface/src/views/apps/chat/components/ChatInput.tsx index 2f443fec2b..5d0524ed43 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatInput.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatInput.tsx @@ -29,7 +29,7 @@ interface ChatInputState { currentInput: string; } -class ChatInput extends Component { +export class ChatInput extends Component { private chatEditor: React.RefObject; constructor(props) { diff --git a/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx b/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx index e41212abfd..74e53d2470 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx @@ -1,9 +1,10 @@ /* eslint-disable max-lines-per-function */ import { BaseImage, Box, Col, Icon, Row, Rule, Text } from '@tlon/indigo-react'; -import { Contact, Post } from '@urbit/api'; +import { Contact, MentionContent, Post } from '@urbit/api'; import bigInt from 'big-integer'; import moment from 'moment'; import React, { + Ref, useEffect, useMemo, useState } from 'react'; @@ -22,13 +23,13 @@ import useLocalState from '~/logic/state/local'; import useSettingsState, { selectCalmState } from '~/logic/state/settings'; import { Dropdown } from '~/views/components/Dropdown'; import ProfileOverlay from '~/views/components/ProfileOverlay'; -import { GraphContent} from '~/views/landscape/components/Graph/GraphContent'; +import { GraphContent } from '~/views/landscape/components/Graph/GraphContent'; export const DATESTAMP_FORMAT = '[~]YYYY.M.D'; interface DayBreakProps { - when: string; + when: string | number; shimTop?: boolean; } @@ -57,7 +58,7 @@ export const DayBreak = ({ when, shimTop = false }: DayBreakProps) => ( ); export const UnreadMarker = React.forwardRef( - ({ dismissUnread }: any, ref) => { + ({ dismissUnread }: any, ref: Ref) => { const [visible, setVisible] = useState(false); const idling = useIdlingState(); @@ -115,7 +116,7 @@ const MessageActionItem = (props) => { ); }; -const MessageActions = ({ api, onReply, onDelete, association, msg, isAdmin, permalink }) => { +const MessageActions = ({ onReply, onDelete, msg, isAdmin, permalink }) => { const isOwn = () => msg.author === window.ship; const { doCopy, copyDisplay } = useCopy(permalink, 'Copy Message Link'); @@ -189,7 +190,7 @@ const MessageWrapper = (props) => { const showHover = (props.transcluded === 0) && hovering && !props.hideHover; return ( void; + dismissUnread?: () => void; api: GlobalApi; highlighted?: boolean; renderSigil?: boolean; @@ -222,27 +223,24 @@ interface ChatMessageProps { innerRef: (el: HTMLDivElement | null) => void; onReply?: (msg: Post) => void; showOurContact: boolean; + onDelete?: () => void; } function ChatMessage(props: ChatMessageProps) { let { highlighted } = props; const { msg, - previousMsg, nextMsg, - isLastRead, - group, - association, + isLastRead = false, className = '', - isPending, + isPending = false, style, isLastMessage, api, showOurContact, - fontSize, hideHover, - dismissUnread, - permalink + dismissUnread = () => null, + permalink = '' } = props; if (typeof msg === 'string' || !msg) { @@ -259,7 +257,7 @@ function ChatMessage(props: ChatMessageProps) { msg.number === 1 ); - const ourMention = msg?.contents?.some((e) => { + const ourMention = msg?.contents?.some((e: MentionContent) => { return e?.mention && e?.mention === window.ship; }); @@ -293,12 +291,10 @@ function ChatMessage(props: ChatMessageProps) { const messageProps = { msg, timestamp, - association, isPending, showOurContact, api, highlighted, - fontSize, hideHover, transcluded, onReply, @@ -423,7 +419,7 @@ export const MessageAuthor = ({ ); return ( - + ( diff --git a/pkg/interface/src/views/apps/chat/components/ChatPane.tsx b/pkg/interface/src/views/apps/chat/components/ChatPane.tsx index ed283c3340..dd6ebf46fb 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatPane.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatPane.tsx @@ -11,7 +11,7 @@ import useGraphState from '~/logic/state/graph'; import ShareProfile from '~/views/apps/chat/components/ShareProfile'; import { Loading } from '~/views/components/Loading'; import SubmitDragger from '~/views/components/SubmitDragger'; -import ChatInput from './ChatInput'; +import ChatInput, { ChatInput as NakedChatInput } from './ChatInput'; import ChatWindow from './ChatWindow'; interface ChatPaneProps { @@ -82,14 +82,14 @@ export function ChatPane(props: ChatPaneProps): ReactElement { } = props; const graphTimesentMap = useGraphState(state => state.graphTimesentMap); const ourContact = useOurContact(); - const chatInput = useRef(); + const chatInput = useRef(); const onFileDrag = useCallback( (files: FileList | File[]) => { if (!chatInput.current) { return; } - chatInput.current?.uploadFiles(files); + (chatInput.current as NakedChatInput)?.uploadFiles(files); }, [chatInput.current] ); diff --git a/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx b/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx index b7ca5a39c5..b721601665 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx @@ -16,7 +16,7 @@ type ChatWindowProps = { unreadCount: number; graph: Graph; graphSize: number; - station: unknown; + station?: unknown; fetchMessages: (newer: boolean) => Promise; api: GlobalApi; scrollTo?: BigInteger; @@ -36,6 +36,11 @@ interface ChatWindowState { unreadIndex: BigInteger; } +interface RendererProps { + index: bigInt.BigInteger; + scrollWindow: any; +} + const virtScrollerStyle = { height: '100%' }; class ChatWindow extends Component< @@ -99,11 +104,12 @@ class ChatWindow extends Component< }); } - dismissedInitialUnread(): void { + dismissedInitialUnread(): boolean { const { unreadCount, graph } = this.props; - return this.state.unreadIndex.eq(bigInt.zero) ? unreadCount > graph.size : - this.state.unreadIndex.neq(graph.keys()?.[unreadCount]?.[0] ?? bigInt.zero); + return this.state.unreadIndex.eq(bigInt.zero) + ? unreadCount > graph.size + : this.state.unreadIndex.neq(graph.keys()?.[unreadCount]?.[0] ?? bigInt.zero); } handleWindowBlur(): void { @@ -173,7 +179,7 @@ class ChatWindow extends Component< } } - renderer = React.forwardRef(({ index, scrollWindow }, ref) => { + renderer = React.forwardRef(({ index, scrollWindow }: RendererProps, ref) => { const { api, showOurContact, diff --git a/pkg/interface/src/views/apps/chat/components/UnreadNotice.tsx b/pkg/interface/src/views/apps/chat/components/UnreadNotice.tsx index ac5a34f89c..a81acf014b 100644 --- a/pkg/interface/src/views/apps/chat/components/UnreadNotice.tsx +++ b/pkg/interface/src/views/apps/chat/components/UnreadNotice.tsx @@ -22,16 +22,16 @@ const UnreadNotice = (props): ReactElement | null => { className='unread-notice' >
- + { if(!graphKeys.has(resource)) { autoJoin(); - } else if(Boolean(association) && 'graph' in association.config) { - history.push(`/~landscape/home/resource/${association.metadata.config.graph}${path}`); + } else if(Boolean(association) && 'graph' in association.metadata.config) { + history.push(`/~landscape/home/resource/${(association.metadata.config as GraphConfig).graph}${path}`); } return (
diff --git a/pkg/interface/src/views/apps/launch/App.tsx b/pkg/interface/src/views/apps/launch/App.tsx index 791a42402b..0d7b783fe6 100644 --- a/pkg/interface/src/views/apps/launch/App.tsx +++ b/pkg/interface/src/views/apps/launch/App.tsx @@ -6,13 +6,13 @@ import { Helmet } from 'react-helmet'; import styled from 'styled-components'; import GlobalApi from '~/logic/api/global'; import { - hasTutorialGroup, + hasTutorialGroup, - TUTORIAL_BOOK, - TUTORIAL_CHAT, TUTORIAL_GROUP, - TUTORIAL_HOST, + TUTORIAL_BOOK, + TUTORIAL_CHAT, TUTORIAL_GROUP, + TUTORIAL_HOST, - TUTORIAL_LINKS + TUTORIAL_LINKS } from '~/logic/lib/tutorialModal'; import { useModal } from '~/logic/lib/useModal'; import { useQuery } from '~/logic/lib/useQuery'; @@ -67,8 +67,8 @@ export const LaunchApp = (props: LaunchAppProps): ReactElement | null => { const hashBox = ( { dismiss(); }; return exitingTut ? ( - + - + You can always restart the tutorial by typing “tutorial” in Leap - + ) : ( - + - Welcome - + Welcome + You have been invited to use Landscape, an interface to chat and interact with communities
Would you like a tour of Landscape?
- + } @@ -125,7 +125,7 @@ export function NotificationWrapper(props: { {children} - + ); }); @@ -67,21 +67,21 @@ export default function NotificationsScreen(props: any): ReactElement { - + Notifications - + diff --git a/pkg/interface/src/views/apps/permalinks/TranscludedNode.tsx b/pkg/interface/src/views/apps/permalinks/TranscludedNode.tsx index c5047e60ad..1dba297736 100644 --- a/pkg/interface/src/views/apps/permalinks/TranscludedNode.tsx +++ b/pkg/interface/src/views/apps/permalinks/TranscludedNode.tsx @@ -1,5 +1,5 @@ import { Anchor, Box, Col, Icon, Row, Text } from '@tlon/indigo-react'; -import { Association, GraphNode, Group, Post } from '@urbit/api'; +import { Association, GraphConfig, GraphNode, Group, Post, ReferenceContent, TextContent, UrlContent } from '@urbit/api'; import bigInt from 'big-integer'; import React from 'react'; import GlobalApi from '~/logic/api/global'; @@ -28,20 +28,21 @@ function TranscludedLinkNode(props: { switch (idx.length) { case 1: - const [{ text }, link] = node.post.contents; + const [{ text }, link] = node.post.contents as [TextContent, UrlContent | ReferenceContent]; if('reference' in link) { const permalink = referenceToPermalink(link).link; return ; } return ( - + - + {text} ); + case 2: return ( - + + - - {post.post.contents[0]?.text} + + {(post.post.contents[0] as TextContent)?.text} - + @@ -160,13 +161,13 @@ export function TranscludedPost(props: { return ( - + ); diff --git a/pkg/interface/src/views/apps/permalinks/app.tsx b/pkg/interface/src/views/apps/permalinks/app.tsx index cfbd8b82ca..3e29a7e5c6 100644 --- a/pkg/interface/src/views/apps/permalinks/app.tsx +++ b/pkg/interface/src/views/apps/permalinks/app.tsx @@ -1,4 +1,4 @@ -import { Association } from '@urbit/api'; +import { Association, GraphConfig } from '@urbit/api'; import React, { useCallback } from 'react'; import { Redirect, Route, Switch @@ -82,7 +82,7 @@ function GroupRoutes(props: { group: string; url: string }) { return ; } diff --git a/pkg/interface/src/views/apps/permalinks/embed.tsx b/pkg/interface/src/views/apps/permalinks/embed.tsx index ac21851c46..cb4203f935 100644 --- a/pkg/interface/src/views/apps/permalinks/embed.tsx +++ b/pkg/interface/src/views/apps/permalinks/embed.tsx @@ -3,14 +3,14 @@ import { Col, Icon, Row, Text } from '@tlon/indigo-react'; -import { Association, GraphNode, resourceFromPath } from '@urbit/api'; +import { Association, GraphConfig, GraphNode, resourceFromPath } from '@urbit/api'; import React, { useCallback, useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import GlobalApi from '~/logic/api/global'; import { getPermalinkForGraph, GraphPermalink as IGraphPermalink, parsePermalink } from '~/logic/lib/permalinks'; -import { getModuleIcon } from '~/logic/lib/util'; +import { getModuleIcon, GraphModule } from '~/logic/lib/util'; import { useVirtualResizeProp } from '~/logic/lib/virtualContext'; import useGraphState from '~/logic/state/graph'; import useMetadataState from '~/logic/state/metadata'; @@ -23,9 +23,9 @@ function GroupPermalink(props: { group: string; api: GlobalApi }) { ); @@ -79,13 +79,13 @@ function GraphPermalink( maxWidth={full ? null : '500px'} border={full ? null : '1'} borderColor="lightGray" - borderRadius="2" + borderRadius={2} onClick={(e) => { e.stopPropagation(); }} > {showTransclusion && index && ( - + @@ -136,10 +136,10 @@ function PermalinkDetails(props: { alignItems="center" justifyContent="space-between" width="100%" - px="2" - py="1" + px={2} + py={1} > - + {title} diff --git a/pkg/interface/src/views/apps/permalinks/graphIndex.tsx b/pkg/interface/src/views/apps/permalinks/graphIndex.tsx index 714731e0b3..3d40197ffc 100644 --- a/pkg/interface/src/views/apps/permalinks/graphIndex.tsx +++ b/pkg/interface/src/views/apps/permalinks/graphIndex.tsx @@ -1,4 +1,4 @@ -import { Association, Group } from '@urbit/api'; +import { Association, GraphConfig, Group } from '@urbit/api'; import _ from 'lodash'; import React from 'react'; import { Redirect, Route, Switch } from 'react-router-dom'; @@ -8,7 +8,7 @@ export function getGraphPermalink( group: Group, index: string ) { - const mod = assoc.metadata.config.graph; + const mod = (assoc.metadata.config as GraphConfig).graph; const groupPath = group.hidden ? '/~landscape/home' : `/~landscape${assoc.group}`; diff --git a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx index 2225fa25a0..7705c649c1 100644 --- a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx @@ -1,8 +1,8 @@ import { - Button, Col, ManagedCheckboxField as Checkbox, ManagedForm as Form, - ManagedTextInputField as Input, + Button, Col, ManagedCheckboxField as Checkbox, ManagedForm as Form, + ManagedTextInputField as Input, - Row, Text + Row, Text } from '@tlon/indigo-react'; import { Formik } from 'formik'; import _ from 'lodash'; @@ -18,9 +18,9 @@ import { ColorInput } from '~/views/components/ColorInput'; import GroupSearch from '~/views/components/GroupSearch'; import { ImageInput } from '~/views/components/ImageInput'; import { - ProfileControls, ProfileHeader, + ProfileControls, ProfileHeader, - ProfileImages, ProfileStatus + ProfileImages, ProfileStatus } from './Profile'; const formSchema = Yup.object({ @@ -61,7 +61,7 @@ export function ProfileHeaderImageEdit(props: any): ReactElement { ) : ( - { diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx index 03151887d2..41c73d7784 100644 --- a/pkg/interface/src/views/apps/profile/components/Profile.tsx +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -16,7 +16,7 @@ export function ProfileHeader(props: any): ReactElement { @@ -27,7 +27,7 @@ export function ProfileHeader(props: any): ReactElement { export function ProfileImages(props: any): ReactElement { const { hideAvatars } = useSettingsState(selectCalmState); - const { contact, hideCover, ship } = { ...props }; + const { contact, hideCover, ship } = props; const hexColor = contact?.color ? `#${uxToHex(contact.color)}` : '#000000'; const anchorRef = useRef(null); @@ -76,7 +76,7 @@ export function ProfileImages(props: any): ReactElement { + {props.children} ); } export function ProfileStatus(props: any): ReactElement { - const { contact } = { ...props }; + const { contact } = props; return ( {ship === `~${window.ship}` ? ( <> { @@ -145,8 +145,8 @@ export function ProfileActions(props: any): ReactElement { history.push(`/~landscape/dm/${ship.substring(1)}`)} diff --git a/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx b/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx index f63a45927c..7c1122f9fb 100644 --- a/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx @@ -45,15 +45,15 @@ export function ViewProfile(props: any): ReactElement {
- +
- + {contact?.bio ? contact.bio : ''}
{(contact?.groups || []).length > 0 && ( - + Pinned Groups {contact?.groups.slice().sort(lengthOrder).map(g => ( diff --git a/pkg/interface/src/views/apps/profile/profile.tsx b/pkg/interface/src/views/apps/profile/profile.tsx index ea73638086..3e1faf914b 100644 --- a/pkg/interface/src/views/apps/profile/profile.tsx +++ b/pkg/interface/src/views/apps/profile/profile.tsx @@ -36,7 +36,7 @@ export default function ProfileScreen(props: any) { border={1} borderColor='lightGray' overflowY='auto' - flexGrow + flexGrow={1} > bind.onDragLeave(e)} - onDragOver={(editor, e) => bind.onDragOver(e)} - onDrop={(editor, e) => bind.onDrop(e)} - onDragEnter={(editor, e) => bind.onDragEnter(e)} + onDragLeave={(editor, e: DragEvent) => bind.onDragLeave(e)} + onDragOver={(editor, e: DragEvent) => bind.onDragOver(e)} + onDrop={(editor, e: DragEvent) => bind.onDrop(e)} + onDragEnter={(editor, e: DragEvent) => bind.onDragEnter(e)} /> {dragging && } diff --git a/pkg/interface/src/views/apps/publish/components/MarkdownField.tsx b/pkg/interface/src/views/apps/publish/components/MarkdownField.tsx index 36708880e0..f779b1c6a4 100644 --- a/pkg/interface/src/views/apps/publish/components/MarkdownField.tsx +++ b/pkg/interface/src/views/apps/publish/components/MarkdownField.tsx @@ -36,7 +36,7 @@ export const MarkdownField = ({ value={value} onChange={setValue} /> - + {error}
diff --git a/pkg/interface/src/views/apps/publish/components/Note.tsx b/pkg/interface/src/views/apps/publish/components/Note.tsx index 34ead4b28e..f609c63af1 100644 --- a/pkg/interface/src/views/apps/publish/components/Note.tsx +++ b/pkg/interface/src/views/apps/publish/components/Note.tsx @@ -1,18 +1,18 @@ -import React, { useState, useEffect } from 'react'; -import { Box, Text, Col, Anchor, Row, Action } from '@tlon/indigo-react'; +import { Action, Anchor, Box, Col, Row, Text } from '@tlon/indigo-react'; +import { Association, Graph, GraphNode, Group } from '@urbit/api'; import bigInt from 'big-integer'; +import React, { useEffect, useState } from 'react'; import { Link, RouteComponentProps } from 'react-router-dom'; import GlobalApi from '~/logic/api/global'; import { roleForShip } from '~/logic/lib/group'; -import { Contacts, GraphNode, Graph, Association, Unreads, Group, Post } from '@urbit/api'; import { getPermalinkForGraph } from '~/logic/lib/permalinks'; -import { GraphContent } from '~/views/landscape/components/Graph/GraphContent'; import { getComments, getLatestRevision } from '~/logic/lib/publish'; import { useCopy } from '~/logic/lib/useCopy'; import { useQuery } from '~/logic/lib/useQuery'; import Author from '~/views/components/Author'; import { Comments } from '~/views/components/Comments'; import { Spinner } from '~/views/components/Spinner'; +import { GraphContent } from '~/views/landscape/components/Graph/GraphContent'; import { NoteNavigation } from './NoteNavigation'; import { Redirect } from 'react-router-dom'; @@ -117,7 +117,7 @@ export function Note(props: NoteProps & RouteComponentProps) { date={post?.['time-sent']} group={group} > - + {copyDisplay} {adminLinks} @@ -128,8 +128,7 @@ export function Note(props: NoteProps & RouteComponentProps) { @@ -48,12 +48,12 @@ function getAdjacentId( return target?.[0] || null; } -function makeNoteUrl(noteId: number) { +function makeNoteUrl(noteId: BigInteger) { return noteId.toString(); } interface NoteNavigationProps { - noteId: number; + noteId: BigInteger; notebook: Graph; baseUrl: string; } diff --git a/pkg/interface/src/views/apps/publish/components/NotePreview.tsx b/pkg/interface/src/views/apps/publish/components/NotePreview.tsx index fd6178e99f..2e6ebe74b1 100644 --- a/pkg/interface/src/views/apps/publish/components/NotePreview.tsx +++ b/pkg/interface/src/views/apps/publish/components/NotePreview.tsx @@ -6,9 +6,9 @@ import ReactMarkdown from 'react-markdown'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; import { - getComments, - getLatestRevision, - getSnippet + getComments, + getLatestRevision, + getSnippet } from '~/logic/lib/publish'; import useHarkState from '~/logic/state/hark'; import Author from '~/views/components/Author'; @@ -37,7 +37,7 @@ export function NotePreviewContent({ snippet }) { style={{ backgroundSize: 'cover', backgroundPosition: 'center' }} > - +
) }} @@ -86,7 +86,7 @@ export function NotePreview(props: NotePreviewProps) { borderRadius={2} alignItems='flex-start' overflow='hidden' - p='2' + p={2} > {title} @@ -96,7 +96,7 @@ export function NotePreview(props: NotePreviewProps) { - + + {association.metadata?.title} @@ -50,7 +50,7 @@ export function Notebook(props: NotebookProps & RouteComponentProps): ReactEleme - + { return ( Writers - Add additional writers to this notebook + Add additional writers to this notebook { label="" maxLength={undefined} /> - + Submit {writers.length > 0 ? <> - Current writers: - {writers} + Current writers: + {writers} : - + All group members can write to this channel } diff --git a/pkg/interface/src/views/apps/settings/components/lib/BackButton.tsx b/pkg/interface/src/views/apps/settings/components/lib/BackButton.tsx index 88145ebf8f..6218bcd58d 100644 --- a/pkg/interface/src/views/apps/settings/components/lib/BackButton.tsx +++ b/pkg/interface/src/views/apps/settings/components/lib/BackButton.tsx @@ -7,7 +7,7 @@ export function BackButton(props: {}) { Landscape Background - - Set an image background + + Set an image background - - Set a hex-based background - + + Set a hex-based background + )} - + diff --git a/pkg/interface/src/views/apps/settings/components/lib/CalmPref.tsx b/pkg/interface/src/views/apps/settings/components/lib/CalmPref.tsx index a3ab0d61dc..b676499160 100644 --- a/pkg/interface/src/views/apps/settings/components/lib/CalmPref.tsx +++ b/pkg/interface/src/views/apps/settings/components/lib/CalmPref.tsx @@ -1,7 +1,7 @@ import { - Col, ManagedToggleSwitchField as Toggle, + Col, ManagedToggleSwitchField as Toggle, - Text + Text } from '@tlon/indigo-react'; import { Form, Formik, FormikHelpers } from 'formik'; import React, { useCallback } from 'react'; @@ -75,8 +75,8 @@ export function CalmPrefs(props: {
- - + + CalmEngine diff --git a/pkg/interface/src/views/apps/settings/components/lib/Debug.tsx b/pkg/interface/src/views/apps/settings/components/lib/Debug.tsx index 66ec23c013..e6b6171721 100644 --- a/pkg/interface/src/views/apps/settings/components/lib/Debug.tsx +++ b/pkg/interface/src/views/apps/settings/components/lib/Debug.tsx @@ -52,7 +52,7 @@ const StoreDebugger = (props: StoreDebuggerProps) => { backgroundColor='white' color='black' border='1px solid transparent' - borderRadius='2' + borderRadius={2} fontSize={1} placeholder="Drill Down" width="100%" @@ -65,7 +65,7 @@ const StoreDebugger = (props: StoreDebuggerProps) => { } }} /> - {text} + {text} } ); @@ -75,8 +75,8 @@ const DebugPane = () => { return ( <> - - + + Debug Menu diff --git a/pkg/interface/src/views/apps/settings/components/lib/DisplayForm.tsx b/pkg/interface/src/views/apps/settings/components/lib/DisplayForm.tsx index 534e5a6192..e7b16009b8 100644 --- a/pkg/interface/src/views/apps/settings/components/lib/DisplayForm.tsx +++ b/pkg/interface/src/views/apps/settings/components/lib/DisplayForm.tsx @@ -1,8 +1,8 @@ import { - Col, + Col, - Label, - ManagedRadioButtonField as Radio, Text + Label, + ManagedRadioButtonField as Radio, Text } from '@tlon/indigo-react'; import { Form, Formik } from 'formik'; import React from 'react'; @@ -89,8 +89,8 @@ export default function DisplayForm(props: DisplayFormProps) { {props => ( - - + + Display Preferences diff --git a/pkg/interface/src/views/apps/settings/components/lib/GroupChannelPicker.tsx b/pkg/interface/src/views/apps/settings/components/lib/GroupChannelPicker.tsx index 59ce838743..3ec7a3c96d 100644 --- a/pkg/interface/src/views/apps/settings/components/lib/GroupChannelPicker.tsx +++ b/pkg/interface/src/views/apps/settings/components/lib/GroupChannelPicker.tsx @@ -5,12 +5,12 @@ import { StatelessToggleSwitchField, Text } from '@tlon/indigo-react'; -import { Association, resourceFromPath } from '@urbit/api'; +import { Association, GraphConfig, resourceFromPath } from '@urbit/api'; import { useField } from 'formik'; import _ from 'lodash'; import React, { useEffect, useState } from 'react'; import { isWatching } from '~/logic/lib/hark'; -import { getModuleIcon } from '~/logic/lib/util'; +import { getModuleIcon, GraphModule } from '~/logic/lib/util'; import useGraphState from '~/logic/state/graph'; import useHarkState from '~/logic/state/hark'; import useMetadataState, { useGraphsForGroup } from '~/logic/state/metadata'; @@ -20,7 +20,7 @@ export function GroupChannelPicker(props: {}) { const associations = useMetadataState(s => s.associations); return ( - + {_.map(associations.groups, (assoc: Association, group: string) => ( ))} @@ -62,7 +62,7 @@ function GroupWithChannels(props: { association: Association }) { display="grid" gridTemplateColumns="24px 24px 1fr 24px 24px" gridTemplateRows="auto" - gridGap="2" + gridGap={2} gridTemplateAreas="'arrow icon title graphToggle groupToggle'" > {Object.keys(joinedGroupGraphs).length > 0 && ( @@ -112,17 +112,17 @@ function Channel(props: { association: Association }) { setValue(!value); }; - const icon = getModuleIcon(metadata.config?.graph); + const icon = getModuleIcon((metadata.config as GraphConfig)?.graph as GraphModule); return ( <> -
+
- + {metadata.title} - + diff --git a/pkg/interface/src/views/apps/settings/components/lib/LeapSettings.tsx b/pkg/interface/src/views/apps/settings/components/lib/LeapSettings.tsx index d628c4aa42..5f3c616cda 100644 --- a/pkg/interface/src/views/apps/settings/components/lib/LeapSettings.tsx +++ b/pkg/interface/src/views/apps/settings/components/lib/LeapSettings.tsx @@ -1,7 +1,7 @@ import { - Col, + Col, - ManagedCheckboxField, Text + ManagedCheckboxField, Text } from '@tlon/indigo-react'; import { Form, useField, useFormikContext } from 'formik'; import _ from 'lodash'; @@ -9,8 +9,8 @@ import React from 'react'; import GlobalApi from '~/logic/api/global'; import useSettingsState, { selectSettingsState } from '~/logic/state/settings'; import { - LeapCategories, - leapCategories + LeapCategories, + leapCategories } from '~/types'; import { FormikOnBlur } from '~/views/components/FormikOnBlur'; import { ShuffleFields } from '~/views/components/ShuffleFields'; @@ -73,9 +73,9 @@ export function LeapSettings(props: { api: GlobalApi; }) { return ( <> - - - + + + Leap @@ -84,7 +84,7 @@ export function LeapSettings(props: { api: GlobalApi; }) { - + Customize default Leap sections diff --git a/pkg/interface/src/views/apps/settings/components/lib/NotificationPref.tsx b/pkg/interface/src/views/apps/settings/components/lib/NotificationPref.tsx index abed89bb11..2cecbf9da7 100644 --- a/pkg/interface/src/views/apps/settings/components/lib/NotificationPref.tsx +++ b/pkg/interface/src/views/apps/settings/components/lib/NotificationPref.tsx @@ -1,7 +1,7 @@ import { - Col, + Col, - ManagedToggleSwitchField as Toggle, Text + ManagedToggleSwitchField as Toggle, Text } from '@tlon/indigo-react'; import { Form, Formik, FormikHelpers } from 'formik'; import _ from 'lodash'; @@ -72,9 +72,9 @@ export function NotificationPreferences(props: { return ( <> - - - + + + Notification Preferences @@ -84,7 +84,7 @@ export function NotificationPreferences(props: { - + - + Activity diff --git a/pkg/interface/src/views/apps/settings/components/lib/S3Form.tsx b/pkg/interface/src/views/apps/settings/components/lib/S3Form.tsx index 4e2b00ce4f..cf07907be5 100644 --- a/pkg/interface/src/views/apps/settings/components/lib/S3Form.tsx +++ b/pkg/interface/src/views/apps/settings/components/lib/S3Form.tsx @@ -1,7 +1,7 @@ import { - Anchor, Col, ManagedForm as Form, ManagedTextInputField as Input, + Anchor, Col, ManagedForm as Form, ManagedTextInputField as Input, - Text + Text } from '@tlon/indigo-react'; import { Formik, FormikHelpers } from 'formik'; import React, { ReactElement, useCallback } from 'react'; @@ -47,7 +47,7 @@ export default function S3Form(props: S3FormProps): ReactElement { return ( <> - + - - + + S3 Storage Setup @@ -72,8 +72,8 @@ export default function S3Form(props: S3FormProps): ReactElement { Learn more @@ -94,8 +94,8 @@ export default function S3Form(props: S3FormProps): ReactElement { - - + + S3 Buckets diff --git a/pkg/interface/src/views/apps/settings/components/lib/Security.tsx b/pkg/interface/src/views/apps/settings/components/lib/Security.tsx index 9ad5d06063..1cb273557b 100644 --- a/pkg/interface/src/views/apps/settings/components/lib/Security.tsx +++ b/pkg/interface/src/views/apps/settings/components/lib/Security.tsx @@ -1,7 +1,7 @@ import { - Button, - Col, - StatelessCheckboxField, Text + Button, + Col, + StatelessCheckboxField, Text } from '@tlon/indigo-react'; import React, { useState } from 'react'; import GlobalApi from '~/logic/api/global'; @@ -16,8 +16,8 @@ export default function SecuritySettings({ api }: SecuritySettingsProps) { return ( <> - - + + Security Preferences @@ -25,17 +25,17 @@ export default function SecuritySettings({ api }: SecuritySettingsProps) { Manage sessions, login credentials and Landscape access - + Log out of this session - + {allSessions ? 'You will be logged out of all browsers that have currently logged into your Urbit.' : 'You will be logged out of your Urbit on this browser.'} setAllSessions(s => !s)} > diff --git a/pkg/interface/src/views/apps/settings/components/settings.tsx b/pkg/interface/src/views/apps/settings/components/settings.tsx index 158cdef78b..769702e130 100644 --- a/pkg/interface/src/views/apps/settings/components/settings.tsx +++ b/pkg/interface/src/views/apps/settings/components/settings.tsx @@ -10,14 +10,14 @@ export function SettingsItem(props: { const { to, title, description } = props; return ( - + - + {title} {description} @@ -28,9 +28,9 @@ export function SettingsItem(props: { export default function Settings(props: {}) { return ( - - - System Preferences + + + System Preferences Configure and customize Landscape + {children} ); @@ -94,13 +94,13 @@ return; - + System Preferences diff --git a/pkg/interface/src/views/apps/term/api.tsx b/pkg/interface/src/views/apps/term/api.tsx index 8216a771dc..077263efc3 100644 --- a/pkg/interface/src/views/apps/term/api.tsx +++ b/pkg/interface/src/views/apps/term/api.tsx @@ -1,6 +1,9 @@ import _ from 'lodash'; export default class Api { + ship: any; + channel: any; + bindPaths: any[]; constructor(ship, channel) { this.ship = ship; this.channel = channel; @@ -10,7 +13,7 @@ export default class Api { bind(path, method, ship = this.ship, appl = 'herm', success, fail) { this.bindPaths = _.uniq([...this.bindPaths, path]); - window.subscriptionId = this.channel.subscribe(ship, appl, path, + (window as any).subscriptionId = this.channel.subscribe(ship, appl, path, (err) => { fail(err); }, diff --git a/pkg/interface/src/views/apps/term/app.tsx b/pkg/interface/src/views/apps/term/app.tsx index 58f1a0cbaa..cd0ba942f1 100644 --- a/pkg/interface/src/views/apps/term/app.tsx +++ b/pkg/interface/src/views/apps/term/app.tsx @@ -12,6 +12,11 @@ import Store from './store'; import Subscription from './subscription'; class TermApp extends Component { + store: Store; + api: any; + subscription: any; + props: any; + state: any; constructor(props) { super(props); this.store = new Store(); @@ -27,7 +32,7 @@ class TermApp extends Component { componentDidMount() { this.resetControllers(); - const channel = new window.channel(); + const channel = new (window as any).channel(); this.api = new Api(this.props.ship, channel); this.store.api = this.api; @@ -61,13 +66,13 @@ class TermApp extends Component { display='flex' > ; + props: any; constructor(props) { super(props); this.state = {}; @@ -69,7 +71,7 @@ belt = { met: 'bac' }; } paste(e) { - const clipboardData = e.clipboardData || window.clipboardData; + const clipboardData = e.clipboardData || (window as any).clipboardData; const clipboardText = clipboardData.getData('Text'); this.props.api.belt({ txt: [...clipboardText] }); e.preventDefault(); @@ -94,18 +96,18 @@ belt = { met: 'bac' }; } } return ( - - + + { // return ( {text} diff --git a/pkg/interface/src/views/apps/term/store.tsx b/pkg/interface/src/views/apps/term/store.tsx index ebc1bce730..d2166083a4 100644 --- a/pkg/interface/src/views/apps/term/store.tsx +++ b/pkg/interface/src/views/apps/term/store.tsx @@ -2,6 +2,9 @@ import { saveAs } from 'file-saver'; import bel from '../../../logic/lib/bel'; export default class Store { + state: any; + api: any; + setState: any; constructor() { this.state = this.initialState(); } @@ -69,6 +72,7 @@ return h; break; case 'sag': blit.sav = blit.sag; + break; case 'sav': const name = blit.sav.path.split('/').slice(-2).join('.'); const buff = new Buffer(blit.sav.file, 'base64'); diff --git a/pkg/interface/src/views/apps/term/subscription.tsx b/pkg/interface/src/views/apps/term/subscription.tsx index c75c679ae1..178246e43f 100644 --- a/pkg/interface/src/views/apps/term/subscription.tsx +++ b/pkg/interface/src/views/apps/term/subscription.tsx @@ -1,4 +1,8 @@ export default class Subscription { + store: any; + api: any; + channel: any; + firstRoundComplete: boolean; constructor(store, api, channel) { this.store = store; this.api = api; @@ -51,13 +55,13 @@ return; console.error('event source error: ', err); console.log('initiating new channel'); this.firstRoundComplete = false; - setTimeout(2000, () => { + setTimeout(() => { this.store.handleEvent({ data: { clear : true } }); this.start(); - }); + }, 2000); } subscribe(path, app) { diff --git a/pkg/interface/src/views/components/Author.tsx b/pkg/interface/src/views/components/Author.tsx index 58b3abc157..761a5b9853 100644 --- a/pkg/interface/src/views/components/Author.tsx +++ b/pkg/interface/src/views/components/Author.tsx @@ -2,6 +2,7 @@ import { BaseImage, Box, Row } from '@tlon/indigo-react'; import moment from 'moment'; import React, { ReactElement, ReactNode, useState } from 'react'; import { useHistory } from 'react-router-dom'; +import GlobalApi from '~/logic/api/global'; import { Sigil } from '~/logic/lib/sigil'; import { useCopy } from '~/logic/lib/useCopy'; import { cite, deSig, useShowNickname, uxToHex } from '~/logic/lib/util'; @@ -20,7 +21,7 @@ interface AuthorProps { unread?: boolean; api?: GlobalApi; size?: number; - lineHeight?: string; + lineHeight?: string | number; } // eslint-disable-next-line max-lines-per-function @@ -106,7 +107,7 @@ export default function Author(props: AuthorProps & PropFunc): React @@ -93,15 +93,15 @@ export function ChipInput(props: ChipInputProps): ReactElement { }, [inputRef.current, addNewChip, newChip]); return ( - + {caption && } - + {meta.error} diff --git a/pkg/interface/src/views/components/ColorInput.tsx b/pkg/interface/src/views/components/ColorInput.tsx index c947ee9d01..cf68ca0e5d 100644 --- a/pkg/interface/src/views/components/ColorInput.tsx +++ b/pkg/interface/src/views/components/ColorInput.tsx @@ -1,10 +1,10 @@ import { - Box, Col, + Box, Col, - ErrorLabel, Label, - Row, + ErrorLabel, Label, + Row, - StatelessTextInput as Input + StatelessTextInput as Input } from '@tlon/indigo-react'; import { useField } from 'formik'; import React, { FormEvent } from 'react'; @@ -40,11 +40,11 @@ export function ColorInput(props: ColorInputProps) { {caption ? ( - - + {meta.error} diff --git a/pkg/interface/src/views/components/CommentItem.tsx b/pkg/interface/src/views/components/CommentItem.tsx index cb2caa2f98..de8ebd88ab 100644 --- a/pkg/interface/src/views/components/CommentItem.tsx +++ b/pkg/interface/src/views/components/CommentItem.tsx @@ -11,8 +11,8 @@ import { getPermalinkForGraph } from '~/logic/lib/permalinks'; import { getLatestCommentRevision } from '~/logic/lib/publish'; import { useCopy } from '~/logic/lib/useCopy'; import useMetadataState from '~/logic/state/metadata'; -import { GraphContent } from '../landscape/components/Graph/GraphContent'; import Author from '~/views/components/Author'; +import { GraphContent } from '../landscape/components/Graph/GraphContent'; const ClickBox = styled(Box)` cursor: pointer; @@ -60,8 +60,9 @@ export function CommentItem(props: CommentItemProps) { }; const ourMention = post?.contents?.some((e) => { - return e?.mention && e?.mention === window.ship; - }); + if (!('mention' in e)) return false; + return e?.mention && e?.mention === window.ship; + }); if (!highlighted) { if (ourMention) { @@ -118,7 +119,7 @@ export function CommentItem(props: CommentItemProps) { return ( - + - + {copyDisplay} {adminLinks} ) { const post = createPost( content, commentNode.post.index, - parseInt(idx + 1, 10) + parseInt((idx + 1).toString(), 10).toString() ); await api.graph.addPost(ship, name, post); history.push(baseUrl); @@ -128,7 +128,7 @@ export function Comments(props: CommentsProps & PropFunc) { const canComment = isWriter(group, association.resource) || association.metadata.vip === 'reader-comments'; return ( - + {( !editCommentId && canComment ? : null )} {( editCommentId ? ( + {children} diff --git a/pkg/interface/src/views/components/DropdownSearch.tsx b/pkg/interface/src/views/components/DropdownSearch.tsx index 7beda190c8..9141b41d24 100644 --- a/pkg/interface/src/views/components/DropdownSearch.tsx +++ b/pkg/interface/src/views/components/DropdownSearch.tsx @@ -1,14 +1,14 @@ import { - Box, - StatelessTextInput as Input + Box, + StatelessTextInput as Input } from '@tlon/indigo-react'; import _ from 'lodash'; import Mousetrap from 'mousetrap'; import React, { - ChangeEvent, - ReactElement, useCallback, - useEffect, useMemo, useRef, - useState + ChangeEvent, + ReactElement, useCallback, + useEffect, useMemo, useRef, + useState } from 'react'; import { useDropdown } from '~/logic/lib/useDropdown'; import { PropFunc } from '~/types/util'; @@ -140,9 +140,9 @@ export function DropdownSearch(props: DropdownSearchProps): ReactElement { /> {dropdown.length !== 0 && query.length !== 0 && ( { body =`\`\`\`%0A${error.stack?.replaceAll('\n', '%0A')}%0A\`\`\``; } return ( - + {code ? code : 'Error'} diff --git a/pkg/interface/src/views/components/FormGroup.tsx b/pkg/interface/src/views/components/FormGroup.tsx index 6d82ee84a8..84a5cc0910 100644 --- a/pkg/interface/src/views/components/FormGroup.tsx +++ b/pkg/interface/src/views/components/FormGroup.tsx @@ -2,9 +2,9 @@ import { Box, Button, Row } from '@tlon/indigo-react'; import { useFormikContext } from 'formik'; import _ from 'lodash'; import React, { - useCallback, useEffect, + useCallback, useEffect, - useMemo, useState + useMemo, useState } from 'react'; import { Prompt } from 'react-router-dom'; import { FormGroupContext, SubmitHandler } from '~/logic/lib/formGroup'; @@ -152,10 +152,10 @@ export function FormGroup(props: { onReset?: () => void; } & PropFunc diff --git a/pkg/interface/src/views/components/FormSubmit.tsx b/pkg/interface/src/views/components/FormSubmit.tsx index 22f3320f29..ad53f6b3f0 100644 --- a/pkg/interface/src/views/components/FormSubmit.tsx +++ b/pkg/interface/src/views/components/FormSubmit.tsx @@ -22,10 +22,10 @@ export function FormSubmit(props: FormSubmitProps): ReactElement { return ( {dirty && !isSubmitting && ( diff --git a/pkg/interface/src/views/components/GroupLink.tsx b/pkg/interface/src/views/components/GroupLink.tsx index 7716823d64..8388b82740 100644 --- a/pkg/interface/src/views/components/GroupLink.tsx +++ b/pkg/interface/src/views/components/GroupLink.tsx @@ -1,4 +1,5 @@ import { Box, Col, Row, Text } from '@tlon/indigo-react'; +import { MetadataUpdatePreview } from '@urbit/api'; import React, { ReactElement, useEffect, useLayoutEffect, useState } from 'react'; import { useHistory } from 'react-router-dom'; import GlobalApi from '~/logic/api/global'; @@ -56,20 +57,20 @@ onClick={(e) => { width="fit-content" flexShrink={1} alignItems="center" - py="2" - pr="2" + py={2} + pr={2} onClick={ joined ? () => history.push(`/~landscape/ship/${name}`) : showModal } cursor='pointer' opacity={preview ? '1' : '0.6'} > - + - + {preview ? preview.metadata.title : name} - {preview ? `${preview.members} members` : 'Fetching member count'} + {preview ? `${preview.members} members` : 'Fetching member count'} diff --git a/pkg/interface/src/views/components/GroupSearch.tsx b/pkg/interface/src/views/components/GroupSearch.tsx index 0675a73da4..eb4c77f744 100644 --- a/pkg/interface/src/views/components/GroupSearch.tsx +++ b/pkg/interface/src/views/components/GroupSearch.tsx @@ -1,10 +1,10 @@ import { - Box, + Box, - Col, + Col, - ErrorLabel, Icon, Label, - Row, Text + ErrorLabel, Icon, Label, + Row, Text } from '@tlon/indigo-react'; import { Association } from '@urbit/api/metadata'; import { FieldArray, useFormikContext } from 'formik'; @@ -132,12 +132,12 @@ export function GroupSearch>(props: Gr {caption && ( -