on main help sign in
fix app/ally subscription and use monkey
commit2d2698cd31f9fb3d29730e1bd1c5020ec363e6df authorJohn Hyde <johnhydefour@gmail.com> dateThu 8 Dec 2022, 00:36 (4 years ago) parenta397efd
13 files changed+206−99
base-desk/mar/kelvin.hoon−28 desk/app/astrolabe.hoon+5−1 ui/scraps/scry thoughts+5 ui/src/components/extensions/AppIcon.svelte+8−8 ui/src/components/extensions/GroupsShipViewExtension.svelte+3−40 ui/src/components/extensions/ProfileShipViewExtension.svelte+52 ui/src/components/pals/PalsShipViewExtension.svelte+2−1 ui/src/components/ship_view/ShipChildrenTabs.svelte+3−3 ui/src/components/ship_view/ShipView.svelte+5−3 ui/src/lib/api.ts+1−1 ui/src/lib/apps.ts+106−6 ui/src/lib/utils.ts+5−1 ui/src/stores/store.ts+11−7
base-desk/mar/kelvin.hoondeleted−28
@@ -1,28 +0,0 @@
1−|_ kal=waft:clay
2−++ grow
3− |%
4− ++ mime `^mime`[/text/x-kelvin (as-octs:mimes:html hoon)]
5− ++ noun kal
6− ++ hoon
7− %+ rap 3
8− %+ turn
9− %+ sort
10− ~(tap in (waft-to-wefts:clay kal))
11− |= [a=weft b=weft]
12− ?: =(lal.a lal.b)
13− (gte num.a num.b)
14− (gte lal.a lal.b)
15− |= =weft
16− (rap 3 '[%' (scot %tas lal.weft) ' ' (scot %ud num.weft) ']\0a' ~)
17− ::
18− ++ txt (to-wain:format hoon)
19− --
20−++ grab
21− |%
22− ++ noun waft:clay
23− ++ mime
24− |= [=mite len=@ud tex=@]
25− (cord-to-waft:clay tex)
26− --
27−++ grad %noun
28−--
desk/app/astrolabe.hoon+5−1
@@ -59,7 +59,11 @@
5959 ?. ?=(?(%0 %1 %2) -.old) `old
6060 (on-naive-state:hc get-nas:hc)
6161 ?> ?=(%3 -.old)
62− [cards-01 this(state old)]
62+ =/ cards=(list card)
63+ =/ ug-vase !>([/astrolabe '/apps/astrolabe/#'])
64+ [%pass /monkey-ug %agent [our.bowl %monkey] %poke [%bind-ug ug-vase]]~
65+ =. cards (weld cards-01 cards)
66+ [cards this(state old)]
6367++ on-poke on-poke:def
6468++ on-watch on-watch:def
6569++ on-leave on-leave:def
ui/scraps/scry thoughtsnew file+5
@@ -0,0 +1,5 @@
1+:: get list of group ids
2+.^((set [ship term]) %gy /(scot %p our)/group-store/(scot %da now)/groups)
3+.^(* %gx /(scot %p our)/group-store/(scot %da now)/groups/ship/~poster-hoster-midlev-mindyr/astrolabe/noun)
4+
5+web+urbitgraph://astrolabe/ship/~midlev-mindyr
ui/src/components/extensions/AppIcon.svelte+8−8
@@ -9,6 +9,8 @@
99
1010 $: desk = path.split('/')[1];
1111 $: appPromise = getAppByPath(path);
12+ $: appUrbitGraphLink = `web+urbitgraph://${path}`;
13+ $: appLink = `/apps/grid/perma?ext=${appUrbitGraphLink}`;
1214
1315 let overrideText = null;
1416
@@ -25,25 +27,24 @@
2527</script>
2628
2729<div class="w-20 text-sm text-center">
28− <div class="w-20 h-20 border border-gray-300 bg-gray-600 text-white rounded-lg overflow-hidden">
30+ <a class="block w-20 h-20 border border-gray-300 bg-gray-600 text-white rounded-lg overflow-hidden"
31+ href={appLink} target="_blank">
2932 {#await appPromise}
3033 <div class="flex h-full items-center">
3134 <LoadingSpinner />
3235 </div>
3336 {:then app}
34− <a style:background-color={uxToHex(app.color)} class="block h-full w-full text-sm"
35− href="web+urbitgraph://{path}" target="_blank"
36− >
37+ <div style:background-color={uxToHex(app.color)} class="h-full w-full text-sm">
3738 {#if app.image}
3839 <img src={app.image} alt="app icon"
3940 class="aspect-square object-cover w-full h-full"
4041 />
4142 {/if}
42− </a>
43+ </div>
4344 {:catch}
44− {path}
45+ {path}
4546 {/await}
46− </div>
47+ </a>
4748 <CopyToClipboard text={path} on:copy={handleSuccessfullyCopied} on:fail={handleFailedCopy} let:copy>
4849 <span on:click={copy}>
4950 {#if overrideText}
@@ -52,7 +53,6 @@
5253 {#await appPromise}
5354 {desk}
5455 {:then app}
55− <!-- {desk} -->
5656 {app.title}
5757 {/await}
5858 {/if}
ui/src/components/extensions/GroupsShipViewExtension.svelte+3−40
@@ -1,52 +1,15 @@
11<script lang="ts">
2− import SvelteMarkdown from 'svelte-markdown';
32 import { uxToHex } from 'lib/utils';
43 import { normalizeId } from 'lib/id';
54 import store from 'stores/store';
6− import Sigil from "@/common/Sigil.svelte";
75 import ExtensionWindow from '@/ExtensionWindow.svelte';
86
97 export let patp: string;
10− $: contact = $store.contacts[normalizeId(patp)];
11− $: color = contact && uxToHex(contact.color);
12− $: somethingToShow = contact && (contact.nickname || contact.cover || contact.avatar || contact.bio);
138</script>
149
15−{#if somethingToShow}
16− <ExtensionWindow name="Groups">
17− <svelte:fragment slot="top-bar">
18− {#if contact.nickname}
19− <div class="grow m-1 flex justify-center align-center">
20− {contact.nickname}
21− </div>
22− {/if}
23− </svelte:fragment>
24− <div class="flex flex-wrap py-2">
25− {#if contact.cover}
26− <img src={contact.cover} alt="profile cover image"
27− class="m-1 -mb-16 w-full h-48 border border-black rounded-lg object-cover min-w-0"
28− />
29− {/if}
30− <div class="flex flex-wrap md:flex-nowrap justify-center">
31− <div class="mx-8 max-w-[128px] min-w-[128px] h-fit grow overflow-hidden rounded-lg">
32− {#if contact.avatar}
33− <img src={contact.avatar} alt="custom avatar"
34− class="aspect-square object-cover max-w-[128px] min-w-0"
35− />
36− {:else}
37− <Sigil patp={patp} size={128} bgColor={color} useNew />
38− {/if}
39− </div>
40− {#if contact.bio}
41− <div class="text-sm p-3 bg-white rounded-tl-lg rounded-br-lg whitespace-pre-line">
42− <SvelteMarkdown source={contact.bio} />
43− </div>
44− {/if}
45− </div>
46− <!-- <p class="whitespace-pre-line">
47− {contact.bio}
48− </p> -->
49− </div>
10+{#if patp}
11+ <ExtensionWindow name="Shared Groups">
12+ TODO: implement for Groups 2, don't bother with Groups 1
5013 </ExtensionWindow>
5114{/if}
5215
ui/src/components/extensions/ProfileShipViewExtension.sveltenew file+52
@@ -0,0 +1,52 @@
1+<script lang="ts">
2+ import SvelteMarkdown from 'svelte-markdown';
3+ import { uxToHex } from 'lib/utils';
4+ import { normalizeId } from 'lib/id';
5+ import store from 'stores/store';
6+ import Sigil from "@/common/Sigil.svelte";
7+ import ExtensionWindow from '@/ExtensionWindow.svelte';
8+
9+ export let patp: string;
10+ $: contact = $store.contacts[normalizeId(patp)];
11+ $: color = contact && uxToHex(contact.color);
12+ $: somethingToShow = contact && (contact.nickname || contact.cover || contact.avatar || contact.bio);
13+</script>
14+
15+{#if somethingToShow}
16+ <ExtensionWindow name="Groups Profile">
17+ <svelte:fragment slot="top-bar">
18+ {#if contact.nickname}
19+ <div class="grow m-1 flex justify-center align-center">
20+ {contact.nickname}
21+ </div>
22+ {/if}
23+ </svelte:fragment>
24+ <div class="flex flex-wrap py-2">
25+ {#if contact.cover}
26+ <img src={contact.cover} alt="profile cover image"
27+ class="m-1 -mb-16 w-full h-48 border border-black rounded-lg object-cover min-w-0"
28+ />
29+ {/if}
30+ <div class="flex flex-wrap md:flex-nowrap justify-center">
31+ <div class="mx-8 max-w-[128px] min-w-[128px] h-fit grow overflow-hidden rounded-lg">
32+ {#if contact.avatar}
33+ <img src={contact.avatar} alt="custom avatar"
34+ class="aspect-square object-cover max-w-[128px] min-w-0"
35+ />
36+ {:else}
37+ <Sigil patp={patp} size={128} bgColor={color} useNew />
38+ {/if}
39+ </div>
40+ {#if contact.bio}
41+ <div class="text-sm p-3 bg-white rounded-tl-lg rounded-br-lg whitespace-pre-line">
42+ <SvelteMarkdown source={contact.bio} />
43+ </div>
44+ {/if}
45+ </div>
46+ <!-- <p class="whitespace-pre-line">
47+ {contact.bio}
48+ </p> -->
49+ </div>
50+ </ExtensionWindow>
51+{/if}
52+
ui/src/components/pals/PalsShipViewExtension.svelte+2−1
@@ -10,9 +10,10 @@
1010 $: pal = getPal($store.pals, patp);
1111 $: palAdded = pal.status == 'outgoing' || pal.status == 'mutual';
1212 $: [buttonText, buttonFunc] = palAdded ? ['Remove Pal', removePal] : ['Add Pal', addPal];
13+ $: itsUs = patp.substring(1) === window.ship;
1314</script>
1415
15−{#if $store.palsInstalled}
16+{#if $store.palsInstalled && !itsUs}
1617 <ExtensionWindow name="%pals" halfWidth>
1718 <svelte:fragment slot="top-bar">
1819 <div class="grow ml-1 my-2 flex justify-center align-center">
ui/src/components/ship_view/ShipChildrenTabs.svelte+3−3
@@ -16,7 +16,7 @@
1616 $: shipClass = clan(patp);
1717 $: azPoint = ['galaxy', 'star', 'planet'].includes(shipClass);
1818 $: canSpawnPoints = ['galaxy', 'star'].includes(shipClass);
19− $: spawnableClassPlural = !canSpawnPoints ? '' : (shipClass === 'galaxy' ? 'Stars' : 'Planets');
19+ $: spawnableClassPlural = !canSpawnPoints ? '' : (shipClass === 'galaxy' ? 'Star' : 'Planet');
2020 $: {
2121 rawSpawnedPoints = null;
2222 if (canSpawnPoints) {
@@ -37,7 +37,7 @@
3737 $: trueSpawnedCount = spawnedCount || spawnedPoints.length;
3838 $: spawnedTab = {
3939 name: 'Spawned',
40− plural: 'Spawned ' + spawnableClassPlural + (trueSpawnedCount > 1 ? 's' : ''),
40+ plural: 'Spawned ' + spawnableClassPlural + (trueSpawnedCount == 1 ? '' : 's'),
4141 promise: rawSpawnedPointsPromise,
4242 points: spawnedPoints,
4343 count: trueSpawnedCount,
@@ -45,7 +45,7 @@
4545 $: moons = filterIdsForChildMoons($store.peers, patp).map(patpToShip);
4646 $: moonsTab = {
4747 name: 'Moons',
48− plural: 'Known Moon' + (moons.length > 1 ? 's' : ''),
48+ plural: 'Known Moon' + (moons.length == 1 ? '' : 's'),
4949 promise: true,
5050 points: moons,
5151 count: moons.length,
ui/src/components/ship_view/ShipView.svelte+5−3
@@ -14,9 +14,10 @@
1414 import CollapsibleContent from '@/CollapsibleContent.svelte';
1515 import ShipChain from './ShipChain.svelte';
1616 import ShipChildrenTabs from './ShipChildrenTabs.svelte';
17− import GroupsShipViewExtension from '@/extensions/GroupsShipViewExtension.svelte';
18− import AppsShipViewExtension from '@/extensions/AppsShipViewExtension.svelte';
17+ import ProfileShipViewExtension from '~/components/extensions/ProfileShipViewExtension.svelte';
1918 import PalsShipViewExtension from '@/pals/PalsShipViewExtension.svelte';
19+ import AppsShipViewExtension from '@/extensions/AppsShipViewExtension.svelte';
20+ // import GroupsShipViewExtension from '~/components/extensions/GroupsShipViewExtension.svelte';
2021
2122 export let patp: string;
2223
@@ -200,9 +201,10 @@
200201 </div>
201202 </div>
202203 <div class="flex flex-wrap shrink min-h-0 h-fit -m-1 mt-2 justify-evenly justify-items-center">
203− <GroupsShipViewExtension {patp} />
204+ <ProfileShipViewExtension {patp} />
204205 <PalsShipViewExtension {patp} />
205206 <AppsShipViewExtension {patp} />
207+ <!-- <GroupsShipViewExtension {patp} /> -->
206208 </div>
207209 {#if azPoint}
208210 <div class="mt-5 border-t">
ui/src/lib/api.ts+1−1
@@ -88,7 +88,7 @@ export function subscribeToContacts(e: (data: any) => void): Promise<any> {
8888 console.error(`Subscription to contact-store/all just get "err"`);
8989 },
9090 quit: () => {
91− console.error(`Subscription to contact-store/all just get "quit"`)
91+ console.error(`Subscription to contact-store/all just get "quit"`);
9292 }
9393 })
9494}
ui/src/lib/apps.ts+106−6
@@ -1,5 +1,8 @@
1+import _get from 'lodash/get';
2+import { compose } from 'lodash/fp';
13import type { Apps } from 'types/store';
24import store from 'stores/store';
5+import { sleep } from 'lib/utils';
36import { api } from 'lib/api';
47import { normalizeId } from 'lib/id';
58
@@ -7,17 +10,26 @@ export function getProvidedApps(patp: string): Promise<any> {
710 return api.scry<any>({ app: 'treaty', path: `/treaties/${patp}` });
811}
912
13+// Unused, use subscription
1014export function getKnownApps(): Promise<any> {
1115 return api.scry<any>({ app: 'treaty', path: `/allies` }).then(processAllies);
1216}
1317
1418export function getApp(ship: string, desk: string): Promise<any> {
15− return api.scry<any>({ app: 'treaty', path: `/treaty/${normalizeId(ship)}/${desk}` });
19+ return getAppByPath(`${normalizeId(ship)}/${desk}`);
1620}
1721
1822// @param path - ship/desk e.g. ~mister-dister-dozzod-dozzod/webterm
19−export function getAppByPath(path: string): Promise<any> {
20− return api.scry<any>({ app: 'treaty', path: `/treaty/${path}` });
23+export async function getAppByPath(path: string, retry: number = 2): Promise<any> {
24+ try {
25+ return await api.scry<any>({ app: 'treaty', path: `/treaty/${path}` });
26+ } catch {
27+ if (retry > 0) {
28+ console.log(`Got error when fetching app: ${path}.\nTrying at most ${retry} more time(s)`);
29+ await sleep(750);
30+ return getAppByPath(path, retry - 1);
31+ }
32+ }
2133}
2234
2335export function getInstalledApps(): Promise<any> {
@@ -30,7 +42,6 @@ export async function sendAllyUpdate(cmd: string, ship: string) {
3042 mark: 'ally-update-0',
3143 json: { [cmd]: normalizeId(ship) },
3244 });
33− // store.refreshKnownApps();
3445 return result;
3546}
3647
@@ -49,7 +60,6 @@ export async function addAllies(ships: string[]) {
4960 results = results.filter(r => r.status === 'fulfilled').map((r) => {
5061 return (r as PromiseFulfilledResult<any>).value;
5162 });
52− store.refreshKnownApps();
5363 return results;
5464}
5565
@@ -60,7 +70,6 @@ export async function delAllies(ships: string[], retry: number = 0) {
6070 results = results.filter(r => r.status === 'fulfilled').map((r) => {
6171 return (r as PromiseFulfilledResult<any>).value;
6272 });
63− store.refreshKnownApps();
6473 return results;
6574}
6675
@@ -73,3 +82,94 @@ export function processAllies(rawPals: any): Apps {
7382 set,
7483 };
7584}
85+
86+export type AllyUpdate = AllyUpdateIni | AllyUpdateAdd | AllyUpdateDel | AllyUpdateNew;
87+
88+export interface AllyUpdateIni {
89+ ini: {
90+ [ship: string]: string[];
91+ }
92+}
93+
94+export interface AllyUpdateNew {
95+ new: {
96+ ship: string;
97+ alliance: string[];
98+ }
99+}
100+
101+export interface AllyUpdateAdd {
102+ add: string;
103+}
104+
105+export interface AllyUpdateDel {
106+ del: string;
107+}
108+
109+export function handleAllyUpdateIni(json: AllyUpdate, apps: Apps): Apps {
110+ const data = _get(json, 'ini', false);
111+ if (data) {
112+ apps = processAllies(json)
113+ }
114+ return apps;
115+};
116+
117+export function handleAllyUpdateNew(json: AllyUpdate, apps: Apps): Apps {
118+ const data = _get(json, 'new', false);
119+ if (data) {
120+ apps = processAllies({
121+ ini: {
122+ ...apps.allies,
123+ [data.ship]: data.alliance,
124+ }
125+ });
126+ }
127+ return apps;
128+};
129+
130+export function handleAllyUpdateAdd(json: AllyUpdate, apps: Apps): Apps {
131+ const data = _get(json, 'add', false);
132+ if (data) {
133+ apps = processAllies({
134+ ini: {
135+ ...apps.allies,
136+ [data]: [],
137+ }
138+ });
139+ }
140+ return apps;
141+};
142+
143+export function handleAllyUpdateDel(json: AllyUpdate, apps: Apps): Apps {
144+ const data = _get(json, 'del', false);
145+ if (data && (data in apps.allies)) {
146+ delete apps.allies[data];
147+ apps = processAllies({
148+ ini: apps.allies,
149+ });
150+ }
151+ return apps;
152+};
153+
154+export function handleAllyUpdateEvent(updateApps) {
155+ return (allyUpdate: AllyUpdate) => {
156+ console.log(`received ally-update: ${Object.keys(allyUpdate)}`);
157+ const reducers = [handleAllyUpdateIni, handleAllyUpdateNew, handleAllyUpdateAdd, handleAllyUpdateDel];
158+ const reducer = compose(reducers.map(r => sta => r(allyUpdate, sta)));
159+ updateApps(reducer);
160+ };
161+}
162+
163+export function subscribeToApps(e: (data: any) => void): Promise<any> {
164+ return api.subscribe({
165+ app: 'treaty',
166+ path: '/allies',
167+ event: handleAllyUpdateEvent(e),
168+ err: () => {
169+ console.error(`Subscription to treaty/all just got "err"`);
170+ },
171+ quit: () => {
172+ console.error(`Subscription to treaty/all just got "quit"`);
173+ }
174+ })
175+}
ui/src/lib/utils.ts+5−1
@@ -54,4 +54,8 @@ export function uxToHex(ux: string) {
5454
5555 value = value.replace('.', '').padStart(6, '0');
5656 return '#' + value;
57−}
57+}
58+
59+export function sleep(ms) {
60+ return new Promise(resolve => setTimeout(resolve, ms));
61+}
ui/src/stores/store.ts+11−7
@@ -2,11 +2,11 @@ import { writable } from 'svelte/store';
22
33import type { Rolodex } from '@urbit/api';
44import { subscribeToContacts, getPeers } from 'lib/api';
5−import type { StoreState } from 'types/store';
5+import type { StoreState, Apps } from 'types/store';
66import { normalizeId } from 'lib/id';
77import { setStoreKey } from 'lib/utils';
88import { getPals } from 'lib/pals';
9−import { getKnownApps } from 'lib/apps';
9+import { subscribeToApps } from 'lib/apps';
1010
1111const initStore: StoreState = {
1212 contacts: {},
@@ -68,11 +68,15 @@ function refreshPals() {
6868}
6969refreshPals();
7070
71−function refreshKnownApps() {
72− return getKnownApps().then((apps) => {
73− setStoreKey(store, 'apps', apps);
71+function updateApps(callback: (apps) => Apps): void {
72+ update($store => {
73+ return {
74+ ...$store,
75+ apps: callback($store.apps),
76+ };
7477 });
7578}
76−refreshKnownApps();
7779
78−export default { subscribe, set, searchPatp, searchSigil, refreshPals, refreshKnownApps, reset };
80+subscribeToApps(updateApps);
81+
82+export default { subscribe, set, searchPatp, searchSigil, refreshPals, reset };