diff --git a/ui/package-lock.json b/ui/package-lock.json index e45681e4..93ef648f 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -23,8 +23,8 @@ "@tlon/sigil-js": "^1.4.4", "@tloncorp/mock-http-api": "^1.2.0", "@types/lodash": "^4.14.172", - "@urbit/api": "^2.2.0", - "@urbit/http-api": "^2.4.5-debug", + "@urbit/aura": "^1.0.0", + "@urbit/js-http-api": "git+https://github.com/urbit/js-http-api", "big-integer": "^1.6.48", "browser-cookies": "^1.2.0", "classnames": "^2.3.1", @@ -49,7 +49,6 @@ "react-hook-form": "^7.38.0", "react-router-dom": "^5.2.0", "slugify": "^1.6.0", - "urbit-ob": "^5.0.1", "zustand": "^3.7.2" }, "devDependencies": { @@ -2402,22 +2401,23 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@urbit/api": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@urbit/api/-/api-2.2.0.tgz", - "integrity": "sha512-W8kP9OT6yOK62n+4yCPO3i9QqU5xriLvZQ9WYW4SAV7ktbSrGuf2kmYbnoqfA/NybIs9Q/MbFkPewrz4XJ96Ag==", - "dependencies": { - "@babel/runtime": "^7.16.0", - "big-integer": "^1.6.48", - "core-js": "^3.19.1", - "immer": "^9.0.1", - "urbit-ob": "^5.0.1" + "node_modules/@urbit/aura": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@urbit/aura/-/aura-1.0.0.tgz", + "integrity": "sha512-IeP3uoDzZ0Rpn345auXK0y/BCcXTmpgAlOPbgf7n4eD35h56OnSoit1kuXKA21sWE19gFjK/wqZcz5ULjz2ADg==", + "engines": { + "node": ">=16", + "npm": ">=8" + }, + "peerDependencies": { + "big-integer": "^1.6.51" } }, - "node_modules/@urbit/http-api": { - "version": "2.4.5-debug", - "resolved": "https://registry.npmjs.org/@urbit/http-api/-/http-api-2.4.5-debug.tgz", - "integrity": "sha512-kMzQwNlrObEz4tEg90nlPRW69Tf+9rD3iIK/JgvsG3423x9oa4rFXobnFKBphXR/5bqd5vR41RoMFN7mqEfDgQ==", + "node_modules/@urbit/js-http-api": { + "name": "@urbit/http-api", + "version": "3.0.0", + "resolved": "git+ssh://git@github.com/urbit/js-http-api.git#25c3f8f73bd8d6edfd4d5b9feffcfe27585e1ddf", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "browser-or-node": "^1.3.0", @@ -2895,8 +2895,9 @@ "license": "MIT" }, "node_modules/big-integer": { - "version": "1.6.49", - "license": "Unlicense", + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", "engines": { "node": ">=0.6" } @@ -2909,10 +2910,6 @@ "node": ">=8" } }, - "node_modules/bn.js": { - "version": "4.12.0", - "license": "MIT" - }, "node_modules/brace-expansion": { "version": "1.1.11", "dev": true, @@ -6107,19 +6104,11 @@ "version": "4.17.21", "license": "MIT" }, - "node_modules/lodash.chunk": { - "version": "4.2.0", - "license": "MIT" - }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "dev": true, "license": "MIT" }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "dev": true, @@ -8450,15 +8439,6 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, - "node_modules/urbit-ob": { - "version": "5.0.1", - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.8", - "lodash.chunk": "^4.2.0", - "lodash.isequal": "^4.5.0" - } - }, "node_modules/uri-js": { "version": "4.4.1", "dev": true, @@ -10520,22 +10500,15 @@ "eslint-visitor-keys": "^2.0.0" } }, - "@urbit/api": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@urbit/api/-/api-2.2.0.tgz", - "integrity": "sha512-W8kP9OT6yOK62n+4yCPO3i9QqU5xriLvZQ9WYW4SAV7ktbSrGuf2kmYbnoqfA/NybIs9Q/MbFkPewrz4XJ96Ag==", - "requires": { - "@babel/runtime": "^7.16.0", - "big-integer": "^1.6.48", - "core-js": "^3.19.1", - "immer": "^9.0.1", - "urbit-ob": "^5.0.1" - } + "@urbit/aura": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@urbit/aura/-/aura-1.0.0.tgz", + "integrity": "sha512-IeP3uoDzZ0Rpn345auXK0y/BCcXTmpgAlOPbgf7n4eD35h56OnSoit1kuXKA21sWE19gFjK/wqZcz5ULjz2ADg==", + "requires": {} }, - "@urbit/http-api": { - "version": "2.4.5-debug", - "resolved": "https://registry.npmjs.org/@urbit/http-api/-/http-api-2.4.5-debug.tgz", - "integrity": "sha512-kMzQwNlrObEz4tEg90nlPRW69Tf+9rD3iIK/JgvsG3423x9oa4rFXobnFKBphXR/5bqd5vR41RoMFN7mqEfDgQ==", + "@urbit/js-http-api": { + "version": "git+ssh://git@github.com/urbit/js-http-api.git#25c3f8f73bd8d6edfd4d5b9feffcfe27585e1ddf", + "from": "@urbit/js-http-api@git+https://github.com/urbit/js-http-api", "requires": { "@babel/runtime": "^7.12.5", "browser-or-node": "^1.3.0", @@ -10835,15 +10808,14 @@ "dev": true }, "big-integer": { - "version": "1.6.49" + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==" }, "binary-extensions": { "version": "2.2.0", "dev": true }, - "bn.js": { - "version": "4.12.0" - }, "brace-expansion": { "version": "1.1.11", "dev": true, @@ -12910,16 +12882,10 @@ "lodash": { "version": "4.17.21" }, - "lodash.chunk": { - "version": "4.2.0" - }, "lodash.clonedeep": { "version": "4.5.0", "dev": true }, - "lodash.isequal": { - "version": "4.5.0" - }, "lodash.merge": { "version": "4.6.2", "dev": true @@ -14350,14 +14316,6 @@ } } }, - "urbit-ob": { - "version": "5.0.1", - "requires": { - "bn.js": "^4.11.8", - "lodash.chunk": "^4.2.0", - "lodash.isequal": "^4.5.0" - } - }, "uri-js": { "version": "4.4.1", "dev": true, diff --git a/ui/package.json b/ui/package.json index 8d8d006d..33a16304 100644 --- a/ui/package.json +++ b/ui/package.json @@ -33,8 +33,8 @@ "@tlon/sigil-js": "^1.4.4", "@tloncorp/mock-http-api": "^1.2.0", "@types/lodash": "^4.14.172", - "@urbit/api": "^2.2.0", - "@urbit/http-api": "^2.4.5-debug", + "@urbit/aura": "^1.0.0", + "@urbit/js-http-api": "git+https://github.com/urbit/js-http-api", "big-integer": "^1.6.48", "browser-cookies": "^1.2.0", "classnames": "^2.3.1", @@ -59,7 +59,6 @@ "react-hook-form": "^7.38.0", "react-router-dom": "^5.2.0", "slugify": "^1.6.0", - "urbit-ob": "^5.0.1", "zustand": "^3.7.2" }, "devDependencies": { diff --git a/ui/src/api.ts b/ui/src/api.ts index bc7815f4..381d819d 100644 --- a/ui/src/api.ts +++ b/ui/src/api.ts @@ -6,7 +6,7 @@ import Urbit, { Thread, UrbitHttpApiEvent, UrbitHttpApiEventType, -} from '@urbit/http-api'; +} from '@urbit/js-http-api'; import _ from 'lodash'; import { useLocalState } from '@/state/local'; import useSchedulerStore from './state/scheduler'; diff --git a/ui/src/components/AppInfo.tsx b/ui/src/components/AppInfo.tsx index b0003299..ad3a9c84 100644 --- a/ui/src/components/AppInfo.tsx +++ b/ui/src/components/AppInfo.tsx @@ -1,4 +1,4 @@ -import { chadIsRunning, Pike, Treaty } from '@urbit/api'; +import { chadIsRunning, Pike, Treaty } from '@/gear'; import clipboardCopy from 'clipboard-copy'; import React, { FC, useCallback, useState } from 'react'; import cn from 'classnames'; diff --git a/ui/src/components/Avatar.tsx b/ui/src/components/Avatar.tsx index 35e7174e..dbea5e1b 100644 --- a/ui/src/components/Avatar.tsx +++ b/ui/src/components/Avatar.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import React, { useMemo } from 'react'; import { sigil, reactRenderer } from '@tlon/sigil-js'; -import { deSig } from '@urbit/api'; +import { deSig } from '@urbit/aura'; import { darken, lighten, parseToHsla } from 'color2k'; import { useCurrentTheme } from '../state/local'; import { normalizeUrbitColor } from '@/logic/utils'; diff --git a/ui/src/components/DocketImage.tsx b/ui/src/components/DocketImage.tsx index 68212342..8ee86237 100644 --- a/ui/src/components/DocketImage.tsx +++ b/ui/src/components/DocketImage.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { Docket } from '@urbit/api'; +import { Docket } from '@/gear'; import cn from 'classnames'; import { useTileColor } from '../tiles/useTileColor'; diff --git a/ui/src/components/PikeMeta.tsx b/ui/src/components/PikeMeta.tsx index 5877fbfa..4e3d9a54 100644 --- a/ui/src/components/PikeMeta.tsx +++ b/ui/src/components/PikeMeta.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Pike } from '@urbit/api'; +import { Pike } from '@/gear'; import { Attribute } from './Attribute'; diff --git a/ui/src/components/ProviderLink.tsx b/ui/src/components/ProviderLink.tsx index 702ff7a4..2e2a179f 100644 --- a/ui/src/components/ProviderLink.tsx +++ b/ui/src/components/ProviderLink.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import React from 'react'; import { Link, LinkProps } from 'react-router-dom'; -import { Provider } from '@urbit/api'; +import { Provider } from '@/gear'; import { ShipName } from './ShipName'; import { Avatar, AvatarSizes } from './Avatar'; import { Contact } from '@/types/contact'; diff --git a/ui/src/components/ProviderList.tsx b/ui/src/components/ProviderList.tsx index 61674b13..abd5e29b 100644 --- a/ui/src/components/ProviderList.tsx +++ b/ui/src/components/ProviderList.tsx @@ -1,5 +1,5 @@ import React, { MouseEvent, useCallback } from 'react'; -import { Provider } from '@urbit/api'; +import { Provider } from '@/gear'; import classNames from 'classnames'; import { MatchItem } from '../nav/Nav'; import { useRecentsStore } from '../nav/search/Home'; diff --git a/ui/src/components/ShipName.tsx b/ui/src/components/ShipName.tsx index 0342508a..b767c69a 100644 --- a/ui/src/components/ShipName.tsx +++ b/ui/src/components/ShipName.tsx @@ -1,4 +1,4 @@ -import { cite } from '@urbit/api'; +import { cite } from '@urbit/aura'; import React, { HTMLAttributes } from 'react'; import { useCalm } from '../state/settings'; import { useContact } from '../state/contact'; diff --git a/ui/src/components/TreatyMeta.tsx b/ui/src/components/TreatyMeta.tsx index 00974bb7..36185d3a 100644 --- a/ui/src/components/TreatyMeta.tsx +++ b/ui/src/components/TreatyMeta.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { daToDate, Treaty } from '@urbit/api'; +import { daToUnix, parseDa } from '@urbit/aura' +import { Treaty } from '@/gear'; import moment from 'moment'; import { Attribute } from './Attribute'; @@ -15,7 +16,7 @@ export function TreatyMeta(props: { treaty: Treaty }) { {ship}/{desk} - {moment(daToDate(cass.da)).format('YYYY.MM.DD')} + {moment(daToUnix(parseDa(cass.da))).format('YYYY.MM.DD')} {meta.map((d) => ( diff --git a/ui/src/gear/contacts/index.ts b/ui/src/gear/contacts/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/ui/src/gear/contacts/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/ui/src/gear/contacts/lib.ts b/ui/src/gear/contacts/lib.ts new file mode 100644 index 00000000..7c024a2c --- /dev/null +++ b/ui/src/gear/contacts/lib.ts @@ -0,0 +1,109 @@ + +import { Patp, Poke, Scry } from '@urbit/js-http-api'; +import { + Contact, + ContactUpdateAdd, + ContactUpdateEdit, + ContactUpdateRemove, + ContactEditField, + ContactShare, + ContactUpdate, + ContactUpdateAllowShips, + ContactUpdateAllowGroup, + ContactUpdateSetPublic +} from './types'; + +export const CONTACT_UPDATE_VERSION = 0; + +const storeAction = (data: T, version: number = CONTACT_UPDATE_VERSION): Poke => ({ + app: 'contact-store', + mark: `contact-update-${version}`, + json: data +}); + +export { storeAction as contactStoreAction }; + +export const addContact = (ship: Patp, contact: Contact): Poke => { + contact['last-updated'] = Date.now(); + + return storeAction({ + add: { ship, contact } + }); +}; + +export const removeContact = (ship: Patp): Poke => + storeAction({ + remove: { ship } + }); + +export const share = (recipient: Patp, version: number = CONTACT_UPDATE_VERSION): Poke => ({ + app: 'contact-push-hook', + mark: 'contact-share', + json: { share: recipient } +}); + +export const editContact = ( + ship: Patp, + editField: ContactEditField +): Poke => + storeAction({ + edit: { + ship, + 'edit-field': editField, + timestamp: Date.now() + } + }); + +export const allowShips = ( + ships: Patp[] +): Poke => storeAction({ + allow: { + ships + } +}); + +export const allowGroup = ( + ship: string, + name: string +): Poke => storeAction({ + allow: { + group: { ship, name } + } +}); + +export const setPublic = ( + setPublic: any +): Poke => { + return storeAction({ + 'set-public': setPublic + }); +}; + +export const retrieve = ( + ship: string +) => { + const resource = { ship, name: '' }; + return { + app: 'contact-pull-hook', + mark: 'pull-hook-action', + json: { + add: { + resource, + ship + } + } + }; +}; + +export const fetchIsAllowed = ( + entity: string, + name: string, + ship: string, + personal: boolean +): Scry => { + const isPersonal = personal ? 'true' : 'false'; + return { + app: 'contact-store', + path: `/is-allowed/${entity}/${name}/${ship}/${isPersonal}` + }; +}; diff --git a/ui/src/gear/contacts/types.ts b/ui/src/gear/contacts/types.ts new file mode 100644 index 00000000..75aa943c --- /dev/null +++ b/ui/src/gear/contacts/types.ts @@ -0,0 +1,82 @@ +import { Path, Patp } from '@urbit/js-http-api'; +import { Resource } from '../groups'; + +export type ContactUpdate = + | ContactUpdateAdd + | ContactUpdateRemove + | ContactUpdateEdit + | ContactUpdateInitial + | ContactUpdateAllowGroup + | ContactUpdateAllowShips + | ContactUpdateSetPublic; + + export interface ContactUpdateAdd { + add: { + ship: Patp; + contact: Contact; + }; +} + +export interface ContactUpdateRemove { + remove: { + ship: Patp; + }; +} + +export interface ContactUpdateEdit { + edit: { + ship: Patp; + 'edit-field': ContactEditField; + timestamp: number; + }; +} + +export interface ContactUpdateAllowShips { + allow: { + ships: Patp[]; + } +} + +export interface ContactUpdateAllowGroup { + allow: { + group: Resource; + } +} + +export interface ContactUpdateSetPublic { + 'set-public': boolean; +} + +export interface ContactShare { + share: Patp; +} + +export interface ContactUpdateInitial { + initial: Rolodex; +} + +export type Rolodex = { + [p in Patp]: Contact; +}; + +export type Contacts = Rolodex; + +export interface Contact { + nickname: string; + bio: string; + status: string; + color: string; + avatar: string | null; + cover: string | null; + groups: Path[]; + 'last-updated': number; +} + +type ContactKeys = keyof Contact; + +export type ContactEditFieldPrim = Exclude; + +export type ContactEditField = Partial> & { + 'add-group'?: Resource; + 'remove-group'?: Resource; +}; diff --git a/ui/src/gear/deps.d.ts b/ui/src/gear/deps.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/ui/src/gear/docket/index.ts b/ui/src/gear/docket/index.ts new file mode 100644 index 00000000..e06143cf --- /dev/null +++ b/ui/src/gear/docket/index.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; diff --git a/ui/src/gear/docket/lib.ts b/ui/src/gear/docket/lib.ts new file mode 100644 index 00000000..ebdce211 --- /dev/null +++ b/ui/src/gear/docket/lib.ts @@ -0,0 +1,65 @@ +import { Poke, Scry } from '@urbit/js-http-api'; +import { Chad } from './types'; + +export function chadIsRunning(chad: Chad) { + return 'glob' in chad || 'site' in chad; +} + +export const scryCharges: Scry = { + app: 'docket', + path: '/charges' +}; + +export const scryDockets: Scry = { + app: 'docket', + path: '/dockets' +}; + +export const scryTreaties: Scry = { + app: 'treaty', + path: '/treaties' +}; + +export const scryDefaultAlly: Scry = { + app: 'treaty', + path: '/default-ally' +}; + +export const scryAllies: Scry = { + app: 'treaty', + path: '/allies' +}; + +export const scryAllyTreaties = (ship: string): Scry => ({ + app: 'treaty', + path: `/treaties/${ship}` +}); + +/** + * Uninstall a desk, and remove docket + */ +export function docketUninstall(desk: string): Poke { + return { + app: 'docket', + mark: 'docket-uninstall', + json: desk + }; +} + +export function docketInstall(ship: string, desk: string): Poke { + return { + app: 'docket', + mark: 'docket-install', + json: `${ship}/${desk}` + }; +} + +export function allyShip(ship: string): Poke { + return { + app: 'treaty', + mark: 'ally-update-0', + json: { + add: ship + } + }; +} diff --git a/ui/src/gear/docket/types.ts b/ui/src/gear/docket/types.ts new file mode 100644 index 00000000..9603ff38 --- /dev/null +++ b/ui/src/gear/docket/types.ts @@ -0,0 +1,160 @@ +import { Cass } from '../hood'; +export type DeskStatus = 'active' | 'suspended'; + +export type DocketHref = DocketHrefSite | DocketHrefGlob; + +export interface DocketHrefGlob { + glob: { + base: string; + + } +} + +export interface DocketHrefSite { + site: string; +} + +export interface Docket { + title: string; + info?: string; + color: string; + href: DocketHref; + website: string; + license: string; + version: string; + image?: string; +} + +export interface Charge extends Docket { + chad: Chad; +} + +export type Chad = HungChad | GlobChad | SiteChad | InstallChad | SuspendChad; + +export interface HungChad { + hung: string; +} + +export interface GlobChad { + glob: null; +} +export interface SiteChad { + site: null; +} +export interface InstallChad { + install: null; + +} +export interface SuspendChad { + suspend: null; +} + +// desk/lib/treaty.hoon +type Vane = 'ames' | 'behn' | 'clay' | 'dill' | 'eyre' | 'gall' | 'iris' | 'jael' | 'khan'; + +type Tail = { + jump?: boolean; + care?: string | null; + desk?: string | null; + dude?: string | null; + path?: string | null; + ship?: string | null; + spur?: string | null; + vane?: string | null; +} | null; + +interface SealPerm { + vane: Vane | null; + name: string; + hoon: string; + tail: Tail; +} + +export type Seal = SealPerm[]; + +export interface Treaty extends Docket { + ship: string; + desk: string; + cass: Cass; + hash: string; + bill: string[]; + seal: Seal; +} + +export interface Charges { + [desk: string]: Charge; +} + +export interface Treaties { + [ref: string]: Treaty; +} + +export type Charter = string[]; + +export interface Allies { + [ship: string]: Charter; +} + +export interface Provider { + shipName: string; + nickname?: string; + status?: string; +} + +export type ChargeUpdate = ChargeUpdateInitial | ChargeUpdateAdd | ChargeUpdateDel; + +export interface ChargeUpdateInitial { + initial: { + [desk: string]: Charge; + } +} + +export interface ChargeUpdateAdd { + 'add-charge': { + desk: string; + charge: Charge; + } +} + +export interface ChargeUpdateDel { + 'del-charge': string; +} + +export type AllyUpdate = AllyUpdateIni | AllyUpdateAdd | AllyUpdateDel | AllyUpdateNew; + +export interface AllyUpdateIni { + ini: { + [ship: string]: string[]; + } +} + +export interface AllyUpdateAdd { + add: string; +} + +export interface AllyUpdateDel { + del: string; +} + +export interface AllyUpdateNew { + new: { + ship: string; + alliance: string[]; + } +} + +export type TreatyUpdate = TreatyUpdateIni | TreatyUpdateAdd | TreatyUpdateDel; + +export interface TreatyUpdateIni { + ini: { + [foreignDesk: string]: Treaty; + } +} + +export interface TreatyUpdateAdd { + add: Treaty; +} + +export interface TreatyUpdateDel { + del: string; +} diff --git a/ui/src/gear/groups/index.ts b/ui/src/gear/groups/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/ui/src/gear/groups/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/ui/src/gear/groups/lib.ts b/ui/src/gear/groups/lib.ts new file mode 100644 index 00000000..2d5d2d50 --- /dev/null +++ b/ui/src/gear/groups/lib.ts @@ -0,0 +1,227 @@ +import { deSig } from '@urbit/aura'; +import { Path, Patp, PatpNoSig, Poke, Thread } from '@urbit/js-http-api'; +import { Enc } from '@/gear'; +import { Group, GroupPolicy, GroupPolicyDiff, GroupUpdateAddMembers, GroupUpdateAddTag, GroupUpdateChangePolicy, GroupUpdateRemoveGroup, GroupUpdateRemoveMembers, GroupUpdateRemoveTag, Resource, RoleTags, Tag } from './types'; +import { GroupUpdate } from './update'; + +export const GROUP_UPDATE_VERSION = 0; + +export const proxyAction = (data: T, version: number = GROUP_UPDATE_VERSION): Poke => ({ + app: 'group-push-hook', + mark: `group-update-${version}`, + json: data +}); + +const storeAction = (data: T, version: number = GROUP_UPDATE_VERSION): Poke => ({ + app: 'group-store', + mark: `group-update-${version}`, + json: data +}); + +export { storeAction as groupStoreAction }; + +const viewAction = (data: T): Poke => ({ + app: 'group-view', + mark: 'group-view-action', + json: data +}); + +export { viewAction as groupViewAction }; + +export const viewThread = (thread: string, action: T): Thread => ({ + inputMark: 'group-view-action', + outputMark: 'json', + threadName: thread, + body: action +}); + +export const removeMembers = ( + resource: Resource, + ships: PatpNoSig[] +): Poke => proxyAction({ + removeMembers: { + resource, + ships + } +}); + +export const addTag = ( + resource: Resource, + tag: Tag, + ships: Patp[] +): Poke => proxyAction({ + addTag: { + resource, + tag, + ships + } +}); + +export const removeTag = ( + tag: Tag, + resource: Resource, + ships: PatpNoSig[] +): Poke => proxyAction({ + removeTag: { + tag, + resource, + ships + } +}); + +export const addMembers = ( + resource: Resource, + ships: PatpNoSig[] +): Poke => proxyAction({ + addMembers: { + resource, + ships + } +}); + +export const removeGroup = ( + resource: Resource +): Poke => storeAction({ + removeGroup: { + resource + } +}); + +export const changePolicy = ( + resource: Resource, + diff: Enc +): Poke> => proxyAction({ + changePolicy: { + resource, + diff + } +}); + +export const join = ( + ship: string, + name: string, + app: "groups" | "graph", + autojoin: boolean, + share: boolean +): Poke => viewAction({ + join: { + resource: makeResource(ship, name), + ship, + shareContact: share || false, + app, + autojoin + } +}); + +export const createGroup = ( + name: string, + policy: Enc, + title: string, + description: string +): Thread => viewThread('group-create', { + create: { + name, + policy, + title, + description + } +}); + +export const deleteGroup = ( + ship: string, + name: string +): Thread => viewThread('group-delete', { + remove: makeResource(ship, name) +}); + +export const leaveGroup = ( + ship: string, + name: string +): Thread => viewThread('group-leave', { + leave: makeResource(ship, name) +}); + +export const invite = ( + ship: string, + name: string, + ships: Patp[], + description: string +): Thread => viewThread('group-invite', { + invite: { + resource: makeResource(ship, name), + ships, + description + } +}); + +export const abortJoin = ( + resource: string +): Poke => viewAction({ + abort: resource +}); + +export const roleTags = ['janitor', 'moderator', 'admin']; +// TODO make this type better? + +export const groupBunts = { + group: (): Group => ({ members: [], tags: { role: {} }, hidden: false, policy: groupBunts.policy() }), + policy: (): GroupPolicy => ({ open: { banned: [], banRanks: [] } }) +}; + +export const joinError = ['no-perms', 'strange', 'abort'] as const; +export const joinResult = ['done', ...joinError] as const; +export const joinLoad = ['start', 'added', 'metadata'] as const; +export const joinProgress = [...joinLoad, ...joinResult] as const; + +export function roleForShip( + group: Group, + ship: PatpNoSig +): RoleTags | undefined { + return roleTags.reduce((currRole, role) => { + const roleShips = group?.tags?.role?.[role]; + return roleShips && roleShips.includes(ship) ? role : currRole; + }, undefined as RoleTags | undefined); +}; + +export function resourceFromPath(path: Path): Resource { + const [, , ship, name] = path.split('/'); + return { ship, name }; +} + +export function makeResource(ship: string, name: string) { + return { ship, name }; +} + +export const isWriter = (group: Group, resource: string, ship: string) => { + const graph = group?.tags?.graph; + const writers: string[] | undefined = graph && (graph[resource] as any)?.writers; + const admins = group?.tags?.role?.admin ?? []; + if (typeof writers === 'undefined') { + return true; + } else { + return [...writers].includes(ship) || admins.includes(ship); + } +}; + +export function isChannelAdmin( + group: Group, + resource: string, + ship: string +): boolean { + const role = roleForShip(group, deSig(ship)); + + return ( + isHost(resource, ship) || + role === 'admin' || + role === 'moderator' + ); +} + +export function isHost( + resource: string, + ship: string +): boolean { + const [, , host] = resource.split('/'); + + return ship === host; +} diff --git a/ui/src/gear/groups/types.ts b/ui/src/gear/groups/types.ts new file mode 100644 index 00000000..6197c4f9 --- /dev/null +++ b/ui/src/gear/groups/types.ts @@ -0,0 +1,2 @@ +export * from './update'; +export * from './view'; \ No newline at end of file diff --git a/ui/src/gear/groups/update.ts b/ui/src/gear/groups/update.ts new file mode 100644 index 00000000..a5f025a1 --- /dev/null +++ b/ui/src/gear/groups/update.ts @@ -0,0 +1,176 @@ +import { PatpNoSig, Path } from '@urbit/js-http-api'; +import { ShipRank, Enc } from '@/gear'; +import { roleTags } from './index'; + +export type RoleTags = typeof roleTags[number]; +interface RoleTag { + tag: 'admin' | 'moderator' | 'janitor'; +} + +interface AppTag { + app: string; + resource: string; + tag: string; +} + +export type Tag = AppTag | RoleTag; + +export interface InvitePolicy { + invite: { + pending: PatpNoSig[]; + }; +} + +export interface OpenPolicy { + open: { + banned: PatpNoSig[]; + banRanks: ShipRank[]; + }; +} + +export interface Resource { + name: string; + ship: PatpNoSig; +} + +export type OpenPolicyDiff = + | AllowRanksDiff + | BanRanksDiff + | AllowShipsDiff + | BanShipsDiff; + +export interface AllowRanksDiff { + allowRanks: ShipRank[]; +} + +export interface BanRanksDiff { + banRanks: ShipRank[]; +} + +export interface AllowShipsDiff { + allowShips: PatpNoSig[]; +} + +export interface BanShipsDiff { + banShips: PatpNoSig[]; +} + +export type InvitePolicyDiff = AddInvitesDiff | RemoveInvitesDiff; + +export interface AddInvitesDiff { + addInvites: PatpNoSig[]; +} + +export interface RemoveInvitesDiff { + removeInvites: PatpNoSig[]; +} + +export interface ReplacePolicyDiff { + replace: GroupPolicy; +} + +export type GroupPolicyDiff = + | { open: OpenPolicyDiff } + | { invite: InvitePolicyDiff } + | ReplacePolicyDiff; + +export type GroupPolicy = OpenPolicy | InvitePolicy; + +export interface TaggedShips { + [tag: string]: PatpNoSig[]; +} + +export interface Tags { + role: TaggedShips; + [app: string]: TaggedShips; +} + +export interface Group { + members: PatpNoSig[]; + tags: Tags; + policy: GroupPolicy; + hidden: boolean; +} + +export type Groups = { + [p in Path]: Group; +}; + +export interface GroupUpdateInitial { + initial: Enc; +} + +export interface GroupUpdateAddGroup { + addGroup: { + resource: Resource; + policy: Enc; + hidden: boolean; + }; +} + +export interface GroupUpdateAddMembers { + addMembers: { + ships: PatpNoSig[]; + resource: Resource; + }; +} + +export interface GroupUpdateRemoveMembers { + removeMembers: { + ships: PatpNoSig[]; + resource: Resource; + }; +} + +export interface GroupUpdateAddTag { + addTag: { + tag: Tag; + resource: Resource; + ships: PatpNoSig[]; + }; +} + +export interface GroupUpdateRemoveTag { + removeTag: { + tag: Tag; + resource: Resource; + ships: PatpNoSig[]; + }; +} + +export interface GroupUpdateChangePolicy { + changePolicy: { resource: Resource; diff: GroupPolicyDiff }; +} + +export interface GroupUpdateRemoveGroup { + removeGroup: { + resource: Resource; + }; +} + +export interface GroupUpdateExpose { + expose: { + resource: Resource; + }; +} + +export interface GroupUpdateInitialGroup { + initialGroup: { + resource: Resource; + group: Enc; + }; +} + +export type GroupUpdate = + | GroupUpdateInitial + | GroupUpdateAddGroup + | GroupUpdateAddMembers + | GroupUpdateRemoveMembers + | GroupUpdateAddTag + | GroupUpdateRemoveTag + | GroupUpdateChangePolicy + | GroupUpdateRemoveGroup + | GroupUpdateExpose + | GroupUpdateInitialGroup; + +export type GroupAction = Omit; diff --git a/ui/src/gear/groups/view.ts b/ui/src/gear/groups/view.ts new file mode 100644 index 00000000..dced81d1 --- /dev/null +++ b/ui/src/gear/groups/view.ts @@ -0,0 +1,30 @@ +import { joinError, joinProgress, joinResult } from "."; +import { Patp } from '@urbit/js-http-api'; + +export type JoinError = typeof joinError[number]; + +export type JoinResult = typeof joinResult[number]; + + +export type JoinProgress = typeof joinProgress[number]; + +export interface JoinRequest { + /** + * Whether to display the join request or not + */ + hidden: boolean; + /** + * Timestamp of when the request started + */ + started: number; + ship: Patp; + progress: JoinProgress; + shareContact: boolean; + autojoin: boolean; + app: 'graph' | 'groups'; + invite: string[]; +} + +export interface JoinRequests { + [rid: string]: JoinRequest; +} diff --git a/ui/src/gear/hark/index.ts b/ui/src/gear/hark/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/ui/src/gear/hark/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/ui/src/gear/hark/lib.ts b/ui/src/gear/hark/lib.ts new file mode 100644 index 00000000..e7f081db --- /dev/null +++ b/ui/src/gear/hark/lib.ts @@ -0,0 +1,163 @@ +import { BigInteger } from 'big-integer'; + +import { Poke } from '@urbit/js-http-api'; +import { + HarkBin, + HarkBinId, + HarkBody, + HarkLid, + HarkPlace +} from './types'; +import { parseUd } from '@urbit/aura'; + +export const harkAction = (data: T): Poke => ({ + app: 'hark-store', + mark: 'hark-action', + json: data +}); + +const graphHookAction = (data: T): Poke => ({ + app: 'hark-graph-hook', + mark: 'hark-graph-hook-action', + json: data +}); + +export { graphHookAction as harkGraphHookAction }; + +const groupHookAction = (data: T): Poke => ({ + app: 'hark-group-hook', + mark: 'hark-group-hook-action', + json: data +}); + +export { groupHookAction as harkGroupHookAction }; + +export const actOnNotification = ( + frond: string, + intTime: BigInteger, + bin: HarkBin +): Poke => + harkAction({ + [frond]: { + time: parseUd(intTime.toString()), + bin + } + }); + +export const setMentions = (mentions: boolean): Poke => + graphHookAction({ + 'set-mentions': mentions + }); + +export const setWatchOnSelf = (watchSelf: boolean): Poke => + graphHookAction({ + 'set-watch-on-self': watchSelf + }); + +export const setDoNotDisturb = (dnd: boolean): Poke => + harkAction({ + 'set-dnd': dnd + }); + +export const addNote = (bin: HarkBin, body: HarkBody) => + harkAction({ + 'add-note': { + bin, + body + } + }); + +export const archive = (bin: HarkBin, lid: HarkLid): Poke => + harkAction({ + archive: { + lid, + bin + } + }); + +export const opened = harkAction({ + opened: null +}); + +export const markCountAsRead = (place: HarkPlace): Poke => + harkAction({ + 'read-count': place + }); + +export const markEachAsRead = ( + place: HarkPlace, + path: string +): Poke => + harkAction({ + 'read-each': { + place, + path + } + }); + +export const seen = () => harkAction({ seen: null }); + +export const readAll = harkAction({ 'read-all': null }); +export const archiveAll = harkAction({ 'archive-all': null }); + +export const ignoreGroup = (group: string): Poke => + groupHookAction({ + ignore: group + }); + +export const ignoreGraph = (graph: string, index: string): Poke => + graphHookAction({ + ignore: { + graph, + index + } + }); + +export const listenGroup = (group: string): Poke => + groupHookAction({ + listen: group + }); + +export const listenGraph = (graph: string, index: string): Poke => + graphHookAction({ + listen: { + graph, + index + } + }); + +/** + * Read all graphs belonging to a particular group + */ +export const readGroup = (group: string) => + harkAction({ + 'read-group': group + }); + +/** + * Read all unreads in a graph + */ +export const readGraph = (graph: string) => + harkAction({ + 'read-graph': graph + }); + +export function harkBinToId(bin: HarkBin): HarkBinId { + const { place, path } = bin; + return `${place.desk}${place.path}${path}`; +} + +export function harkBinEq(a: HarkBin, b: HarkBin): boolean { + return ( + a.place.path === b.place.path && + a.place.desk === b.place.desk && + a.path === b.path + ); +} + +export function harkLidToId(lid: HarkLid): string { + if('time' in lid) { + return `archive-${lid.time}`; + } + return Object.keys(lid)[0]; +} diff --git a/ui/src/gear/hark/types.ts b/ui/src/gear/hark/types.ts new file mode 100644 index 00000000..e52912cb --- /dev/null +++ b/ui/src/gear/hark/types.ts @@ -0,0 +1,58 @@ + +export interface HarkStats { + count: number; + each: string[]; + last: number; +} + +export interface Timebox { + [binId: string]: Notification; +} + +export type HarkContent = { ship: string; } | { text: string; }; + +export interface HarkBody { + title: HarkContent[]; + time: number; + content: HarkContent[]; + link: string; + binned: string; +} + +export interface HarkPlace { + desk: string; + path: string; +} + +export interface HarkBin { + path: string; + place: HarkPlace; +} + +export type HarkLid = + { unseen: null; } +| { seen: null; } +| { time: string; }; + +export type HarkBinId = string; +export interface Notification { + bin: HarkBin; + time: number; + body: HarkBody[]; +} + +export interface NotificationGraphConfig { + watchOnSelf: boolean; + mentions: boolean; + watching: WatchedIndex[] +} + +export interface Unreads { + [path: string]: HarkStats; +} + +interface WatchedIndex { + graph: string; + index: string; +} +export type GroupNotificationsConfig = string[]; diff --git a/ui/src/gear/hood/index.ts b/ui/src/gear/hood/index.ts new file mode 100644 index 00000000..e06143cf --- /dev/null +++ b/ui/src/gear/hood/index.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; diff --git a/ui/src/gear/hood/lib.ts b/ui/src/gear/hood/lib.ts new file mode 100644 index 00000000..346980a6 --- /dev/null +++ b/ui/src/gear/hood/lib.ts @@ -0,0 +1,127 @@ +import { Poke, Scry } from '@urbit/js-http-api'; +import { Pike } from './types'; + +export const getPikes: Scry = { + app: 'hood', + path: '/kiln/pikes' +}; + +/** + * Install a foreign desk + */ +export function kilnInstall( + ship: string, + desk: string, + local?: string +): Poke { + return { + app: 'hood', + mark: 'kiln-install', + json: { + ship, + desk, + local: local || desk + } + }; +} + +/** + * Sync with a foreign desk + */ +export function kilnSync( + ship: string, + desk: string, + local?: string +): Poke { + return { + app: 'hood', + mark: 'kiln-sync', + json: { + ship, + desk, + local: local || desk + } + }; +} + +/** + * Unsync with a foreign desk + */ +export function kilnUnsync( + ship: string, + desk: string, + local?: string +): Poke { + return { + app: 'hood', + mark: 'kiln-unsync', + json: { + ship, + desk, + local: local || desk + } + }; +} + +/** + * Uninstall a desk + */ +export function kilnUninstall( + desk: string +): Poke { + return { + app: 'hood', + mark: 'kiln-uninstall', + json: desk + }; +} + +export function kilnSuspend( + desk: string +): Poke { + return { + app: 'hood', + mark: 'kiln-suspend', + json: desk + }; +} + +export function kilnRevive( + desk: string +): Poke { + return { + app: 'hood', + mark: 'kiln-revive', + json: desk + }; +} + +export function kilnBump(): Poke { + return { + app: 'hood', + mark: 'kiln-bump', + json: null, + }; +} + +export function kilnPause(desk: string) { + return { + app: 'hood', + mark: 'kiln-pause', + json: desk + }; +} + +export function kilnResume(desk: string) { + return { + app: 'hood', + mark: 'kiln-resume', + json: desk + }; +} + +export const scryLag: Scry = ({ app: 'hood', path: '/kiln/lag' }); + +export function getPikePublisher(pike: Pike) { + return pike.sync?.ship; +} diff --git a/ui/src/gear/hood/types.ts b/ui/src/gear/hood/types.ts new file mode 100644 index 00000000..d39110f4 --- /dev/null +++ b/ui/src/gear/hood/types.ts @@ -0,0 +1,222 @@ +import { Perm } from "../permissions"; + +/** + * A pending commit, awaiting a future kelvin version + */ +interface Woof { + aeon: number; + weft: Weft; +} + +interface Rein { + /** + * Agents not in manifest that should be running + */ + add: string[]; + /** + * Agents in manifest that should not be running + */ + sub: string[]; +} + +export interface Rail { + /** + * Original publisher of desk, if available + */ + publisher: string | null; + /** + * Ship of foreign vat + */ + ship: string; + /** + * Desk of foreign vat + */ + desk: string; + /** + * Aeon (version number) that we currently have synced + */ + aeon: number; + next: Woof[]; + paused: boolean; +} + +/** + * A tracker of a foreign {@link Vat} + * + */ +export interface Arak { + rein: Rein; + rail: Rail | null; +} + +/** + * A component's kelvin version + */ +export interface Weft { + /** + * Name of the component + * + * @remarks + * Usually %zuse, %hoon, or %lull + */ + name: string; + /** + * Kelvin version + * + */ + kelvin: number; +} + +export interface KilnDiffBlock { + block: { + desk: string; + arak: Arak; + weft: Weft; + blockers: string[]; + }; +} + +export interface KilnDiffReset { + reset: { + desk: string; + arak: Arak; + }; +} + +export interface KilnDiffMerge { + merge: { + desk: string; + arak: Arak; + }; +} + +export interface KilnDiffMergeSunk { + 'merge-sunk': { + desk: string; + arak: Arak; + tang: string; + }; +} + +export interface KilnDiffMergeFail { + 'merge-fail': { + desk: string; + arak: Arak; + tang: string; + }; +} + +export type KilnDiff = + | KilnDiffBlock + | KilnDiffReset + | KilnDiffMerge + | KilnDiffMergeSunk + | KilnDiffMergeFail; + +/** + * Cases for revision + * + */ +export interface Cass { + /** + * Revision number + */ + ud: number; + /** + * Timestamp of revision, as stringifed `@da` + * + * @remarks + * If \@da is outside valid positive unix timestamp, value will be zero + */ + da: string; +} + +/** + * A local desk installation + */ +export interface Vat { + /** + * Desk that this Vat describes + */ + desk: string; + /** + * Hash of the desk, rendered as `@uv` + * + * @remarks + * Equivalent to + * ```hoon + * .^(@uv %cz /=desk=) + * ``` + */ + hash: string; + /** + * Current revision + */ + cass: Cass; + /** + * Foreign sync + */ + arak: Arak; +} + +export interface Vats { + [desk: string]: Vat; +} + +/** + * Update config & status for desk + */ +export interface Pike { + /** + * The sync source ship and desk for this Pike + * + */ + sync: { + /** + * Source desk for this Pike + */ + desk: string; + /** + * Source ship for this Pike + */ + ship: string; + } | null; + /** + * Hash of the desk, rendered as `@uv` + * + * @remarks + * Equivalent to + * ```hoon + * .^(@uv %cz /=desk=) + * ``` + */ + hash: string; + /** + * how live is this pike? + * + * live - app is running + * held - app is not running, but is trying to run. this state can be entered + * in two main ways: + * - when installing an app but it hasn't finished downloading (or it did + * but failed to install for some reason) + * - when user forced a kelvin upgrade by suspending desks. + * dead - app is not running + */ + zest: "live" | "dead" | "held"; + /** + * {@link Weft}s associated with this Pike + */ + wefts: Weft[]; + /** + * {@link Perm}s granted to this Pike + */ + perms: Perm[]; + /** + * {@link Perm}s that this Pike lacks; required to run + */ + lacks: Perm[]; +} + +export interface Pikes { + [desk: string]: Pike; +} diff --git a/ui/src/gear/index.ts b/ui/src/gear/index.ts new file mode 100644 index 00000000..823bf045 --- /dev/null +++ b/ui/src/gear/index.ts @@ -0,0 +1,18 @@ +export * from './contacts'; +export * as contacts from './contacts'; +export * from './groups'; +export * as groups from './groups'; +export * from './hark'; +export * as hark from './hark'; +export * from './settings'; +export * as settings from './settings'; +export * from './storage'; +export * as storage from './storage'; +export * from './hood'; +export * as hood from './hood'; +export * from './docket'; +export * as docket from './docket'; +export * from './utils'; +export * as utils from './utils'; +export * from './permissions'; +export * as permissions from './permissions'; diff --git a/ui/src/gear/permissions/index.ts b/ui/src/gear/permissions/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/ui/src/gear/permissions/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/ui/src/gear/permissions/lib.ts b/ui/src/gear/permissions/lib.ts new file mode 100644 index 00000000..693da49f --- /dev/null +++ b/ui/src/gear/permissions/lib.ts @@ -0,0 +1 @@ +export {} \ No newline at end of file diff --git a/ui/src/gear/permissions/types.ts b/ui/src/gear/permissions/types.ts new file mode 100644 index 00000000..4956b3ba --- /dev/null +++ b/ui/src/gear/permissions/types.ts @@ -0,0 +1,88 @@ +/** + * A server identity + */ +type Dude = string; + +/** + * path - ship desk case spur + */ +type Spur = string; + +/** + * specific or any desk, at or under spur prefix + */ +interface Burr { + desk: string | null; + spur: Spur; +} + +/** + * burr with specific or any care + */ +interface Spar { + care: string | null; + burr: Burr; +} + +interface PokePerm { + "write": { + jump: boolean; + dude: Dude | null; + } +} + +interface SubscribePerm { + "watch": { + jump: boolean; + dude: Dude | null; + path: string; + } +} + +interface ScryPerm { + "reads": { + vane: string; + spar: Spar; + } +} + +interface PressPerm { + "press": { + spur: Spur; + } +} + +/** + * A system permission + */ +export type Perm = PokePerm | SubscribePerm | ScryPerm | PressPerm; + +/** + * Per lib/perms.hoon, Passport is intended for consumption by permission + * management frontends. + */ +export interface Passport { + /** + * Categorized perms + */ + rad: Perm[]; + /** + * Dangerous perms + */ + sys: Perm[]; + /** + * All apps perms + */ + any: Perm[]; + /** + * Unknown app perms + */ + new: Perm[]; + /** + * Specific app perms + */ + app: { + app: string; + pes: Perm[]; + }[]; +} diff --git a/ui/src/gear/settings/index.ts b/ui/src/gear/settings/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/ui/src/gear/settings/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/ui/src/gear/settings/lib.ts b/ui/src/gear/settings/lib.ts new file mode 100644 index 00000000..7a868ec2 --- /dev/null +++ b/ui/src/gear/settings/lib.ts @@ -0,0 +1,78 @@ +import { Poke, Scry } from '@urbit/js-http-api'; +import { PutBucket, Key, Bucket, DelBucket, Value, PutEntry, DelEntry, SettingsUpdate } from './types'; + +export const action = (data: T): Poke => ({ + app: 'settings-store', + mark: 'settings-event', + json: data +}); + +export const putBucket = ( + desk: string, + key: Key, + bucket: Bucket +): Poke => action({ + 'put-bucket': { + desk, + 'bucket-key': key, + 'bucket': bucket + } +}); + +export const delBucket = ( + desk: string, + key: Key +): Poke => action({ + 'del-bucket': { + desk, + 'bucket-key': key + } +}); + +export const putEntry = ( + desk: string, + bucket: Key, + key: Key, + value: Value +): Poke => action({ + 'put-entry': { + desk, + 'bucket-key': bucket, + 'entry-key': key, + value: value + } +}); + +export const delEntry = ( + desk: string, + bucket: Key, + key: Key +): Poke => action({ + 'del-entry': { + desk, + 'bucket-key': bucket, + 'entry-key': key + } +}); + +export const getAll: Scry = { + app: 'settings-store', + path: '/all' +}; + +export const getBucket = (desk: string, bucket: string) => ({ + app: 'settings-store', + path: `/bucket/${bucket}` +}); + +export const getEntry = (desk: string, bucket: string, entry: string) => ({ + app: 'settings-store', + path: `/entry/${desk}/${bucket}/${entry}` +}); + +export const getDeskSettings = (desk: string) => ({ + app: 'settings-store', + path: `/desk/${desk}` +}); + +export * from './types'; diff --git a/ui/src/gear/settings/types.ts b/ui/src/gear/settings/types.ts new file mode 100644 index 00000000..af02c70b --- /dev/null +++ b/ui/src/gear/settings/types.ts @@ -0,0 +1,64 @@ +export type Key = string; +export type Value = string | string[] | boolean | number; +export type Bucket = { [key: string]: Value; }; +export type DeskSettings = { [bucket: string]: Bucket; }; +export type Settings = { [desk: string]: Settings; } + +export interface PutBucket { + 'put-bucket': { + desk: string; + 'bucket-key': Key; + 'bucket': Bucket; + }; +} + +export interface DelBucket { + 'del-bucket': { + desk: string; + 'bucket-key': Key; + }; +} + +export interface PutEntry { + 'put-entry': { + 'bucket-key': Key; + 'entry-key': Key; + 'value'?: Value; + }; +} + +export interface DelEntry { + 'del-entry': { + desk: string; + 'bucket-key': Key; + 'entry-key': Key; + }; +} + +export interface AllData { + 'all': Settings; +} + +export interface DeskData { + desk: DeskSettings; +} + +export interface BucketData { + 'bucket': Bucket; +} + +export interface EntryData { + 'entry': Value; +} + +export type SettingsUpdate = + | PutBucket + | DelBucket + | PutEntry + | DelEntry; + +export type SettingsData = + | AllData + | BucketData + | EntryData + | DeskData; diff --git a/ui/src/gear/storage/index.ts b/ui/src/gear/storage/index.ts new file mode 100644 index 00000000..4fed660f --- /dev/null +++ b/ui/src/gear/storage/index.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; \ No newline at end of file diff --git a/ui/src/gear/storage/lib.ts b/ui/src/gear/storage/lib.ts new file mode 100644 index 00000000..dd8106b9 --- /dev/null +++ b/ui/src/gear/storage/lib.ts @@ -0,0 +1,47 @@ +import { Poke } from '@urbit/js-http-api'; +import { StorageUpdate, StorageUpdateCurrentBucket, StorageUpdateAddBucket, StorageUpdateRemoveBucket, StorageUpdateEndpoint, StorageUpdateAccessKeyId, StorageUpdateSecretAccessKey } from './types'; + +const s3Action = ( + data: any +): Poke => ({ + app: 's3-store', + mark: 's3-action', + json: data +}); + +export const setCurrentBucket = ( + bucket: string +): Poke => s3Action({ + 'set-current-bucket': bucket +}); + +export const addBucket = ( + bucket: string +): Poke => s3Action({ + 'add-bucket': bucket +}); + +export const removeBucket = ( + bucket: string +): Poke => s3Action({ + 'remove-bucket': bucket +}); + +export const setEndpoint = ( + endpoint: string +): Poke => s3Action({ + 'set-endpoint': endpoint +}); + +export const setAccessKeyId = ( + accessKeyId: string +): Poke => s3Action({ + 'set-access-key-id': accessKeyId +}); + +export const setSecretAccessKey = ( + secretAccessKey: string +): Poke => s3Action({ + 'set-secret-access-key': secretAccessKey +}); + diff --git a/ui/src/gear/storage/types.ts b/ui/src/gear/storage/types.ts new file mode 100644 index 00000000..6c5cb93e --- /dev/null +++ b/ui/src/gear/storage/types.ts @@ -0,0 +1,60 @@ +export interface StorageCredentials { + endpoint: string; + accessKeyId: string; + secretAccessKey: string; +} + +export interface StorageConfiguration { + buckets: Set; + currentBucket: string; +} + +export interface StorageState { + configuration: StorageConfiguration; + credentials: StorageCredentials | null; +} + +export interface StorageUpdateCredentials { + credentials: StorageCredentials; +} + +export interface StorageUpdateConfiguration { + configuration: { + buckets: string[]; + currentBucket: string; + } +} + +export interface StorageUpdateCurrentBucket { + setCurrentBucket: string; +} + +export interface StorageUpdateAddBucket { + addBucket: string; +} + +export interface StorageUpdateRemoveBucket { + removeBucket: string; +} + +export interface StorageUpdateEndpoint { + setEndpoint: string; +} + +export interface StorageUpdateAccessKeyId { + setAccessKeyId: string; +} + +export interface StorageUpdateSecretAccessKey { + setSecretAccessKey: string; +} + +export type StorageUpdate = + StorageUpdateCredentials +| StorageUpdateConfiguration +| StorageUpdateCurrentBucket +| StorageUpdateAddBucket +| StorageUpdateRemoveBucket +| StorageUpdateEndpoint +| StorageUpdateAccessKeyId +| StorageUpdateSecretAccessKey; diff --git a/ui/src/gear/utils/BigIntArrayOrderedMap.ts b/ui/src/gear/utils/BigIntArrayOrderedMap.ts new file mode 100644 index 00000000..dcd1ec37 --- /dev/null +++ b/ui/src/gear/utils/BigIntArrayOrderedMap.ts @@ -0,0 +1,151 @@ +import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; +import bigInt, { BigInteger } from 'big-integer'; + +setAutoFreeze(false); + +enablePatches(); + +export function stringToArr(str: string) { + return str.split('/').slice(1).map((ind) => { + return bigInt(ind); + }); +} + +export function arrToString(arr: BigInteger[]) { + let string = ''; + arr.forEach((key) => { + string = string + `/${key.toString()}`; + }); + return string; +} + +function sorted(a: BigInteger[], b: BigInteger[], reversed = false) { + const getSort = sortBigIntArr(a, b); + if (reversed) { + return getSort * -1; + } else { + return getSort; + } +} + +export function sortBigIntArr(a: BigInteger[], b: BigInteger[]) { + const aLen = a.length; + const bLen = b.length; + + const aCop = a.slice(0); + const bCop = b.slice(0); + aCop.reverse(); + bCop.reverse(); + + let i = 0; + while (i < aLen && i < bLen) { + if (aCop[i].lt(bCop[i])) { + return 1; + } else if (aCop[i].gt(bCop[i])) { + return -1; + } else { + i++; + } + } + + return bLen - aLen; +} + +export class BigIntArrayOrderedMap implements Iterable<[BigInteger[], V]> { + root: Record = {} + cachedIter: [BigInteger[], V][] | null = null; + [immerable] = true; + reversed = false; + + constructor(items: [BigInteger[], V][] = [], reversed = false) { + items.forEach(([key, val]) => { + this.set(key, val); + }); + this.reversed = reversed; + } + + get size() { + return Object.keys(this.root).length; + } + + get(key: BigInteger[]) { + return this.root[arrToString(key)] ?? null; + } + + gas(items: [BigInteger[], V][]) { + return produce(this, (draft) => { + items.forEach(([key, value]) => { + draft.root[arrToString(key)] = castDraft(value); + }); + draft.generateCachedIter(); + }, + (patches) => { + // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); + }); + } + + set(key: BigInteger[], value: V) { + return produce(this, (draft) => { + draft.root[arrToString(key)] = castDraft(value); + draft.cachedIter = null; + }); + } + + clear() { + return produce(this, (draft) => { + draft.cachedIter = []; + draft.root = {}; + }); + } + + has(key: BigInteger[]) { + return arrToString(key) in this.root; + } + + delete(key: BigInteger[]) { + const result = produce(this, (draft) => { + delete draft.root[arrToString(key)]; + draft.cachedIter = null; + }); + return result; + } + + [Symbol.iterator](): IterableIterator<[BigInteger[], V]> { + let idx = 0; + const result = this.generateCachedIter(); + return { + [Symbol.iterator]: this[Symbol.iterator], + next: (): IteratorResult<[BigInteger[], V]> => { + if (idx < result.length) { + return { value: result[idx++], done: false }; + } + return { done: true, value: null }; + } + }; + } + + peekLargest() { + const sorted = Array.from(this); + return sorted[0] as [BigInteger[], V] | null; + } + + peekSmallest() { + const sorted = Array.from(this); + return sorted[sorted.length - 1] as [BigInteger[], V] | null; + } + + keys() { + return Array.from(this).map(([k,v]) => k); + } + + generateCachedIter() { + if(this.cachedIter) { + return [...this.cachedIter]; + } + const result = Object.keys(this.root).map((key) => { + return [stringToArr(key), this.root[key]] as [BigInteger[], V]; + }).sort(([a], [b]) => sorted(a, b, this.reversed)); + this.cachedIter = result; + return [...result]; + } +} diff --git a/ui/src/gear/utils/BigIntOrderedMap.ts b/ui/src/gear/utils/BigIntOrderedMap.ts new file mode 100644 index 00000000..621c2e11 --- /dev/null +++ b/ui/src/gear/utils/BigIntOrderedMap.ts @@ -0,0 +1,116 @@ +import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; +import bigInt, { BigInteger } from 'big-integer'; + +setAutoFreeze(false); + +enablePatches(); + +function sortBigInt(a: BigInteger, b: BigInteger) { + if (a.lt(b)) { + return 1; + } else if (a.eq(b)) { + return 0; + } else { + return -1; + } +} +export class BigIntOrderedMap implements Iterable<[BigInteger, V]> { + root: Record = {} + cachedIter: [BigInteger, V][] | null = null; + [immerable] = true; + + constructor(items: [BigInteger, V][] = []) { + items.forEach(([key, val]) => { + this.set(key, val); + }); + } + + get size() { + if(this.cachedIter) { + return this.cachedIter.length; + } + return this.generateCachedIter().length; + } + + get(key: BigInteger) { + return this.root[key.toString()] ?? null; + } + + gas(items: [BigInteger, V][]) { + return produce(this, (draft) => { + items.forEach(([key, value]) => { + draft.root[key.toString()] = castDraft(value); + }); + draft.cachedIter = null; + }, + (patches) => { + // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); + }); + } + + set(key: BigInteger, value: V) { + return produce(this, (draft) => { + draft.root[key.toString()] = castDraft(value); + draft.cachedIter = null; + }); + } + + clear() { + return produce(this, (draft) => { + draft.cachedIter = []; + draft.root = {}; + }); + } + + has(key: BigInteger) { + return key.toString() in this.root; + } + + delete(key: BigInteger) { + const result = produce(this, (draft) => { + delete draft.root[key.toString()]; + draft.cachedIter = null; + }); + return result; + } + + [Symbol.iterator](): IterableIterator<[BigInteger, V]> { + let idx = 0; + const result = this.generateCachedIter(); + return { + [Symbol.iterator]: this[Symbol.iterator], + next: (): IteratorResult<[BigInteger, V]> => { + if (idx < result.length) { + return { value: result[idx++], done: false }; + } + return { done: true, value: null }; + } + }; + } + + peekLargest() { + const sorted = Array.from(this); + return sorted[0] as [BigInteger, V] | null; + } + + peekSmallest() { + const sorted = Array.from(this); + return sorted[sorted.length - 1] as [BigInteger, V] | null; + } + + keys() { + return Array.from(this).map(([k,v]) => k); + } + + generateCachedIter() { + if(this.cachedIter) { + return [...this.cachedIter]; + } + const result = Object.keys(this.root).map((key) => { + const num = bigInt(key); + return [num, this.root[key]] as [BigInteger, V]; + }).sort(([a], [b]) => sortBigInt(a,b)); + this.cachedIter = result; + return [...result]; + } +} diff --git a/ui/src/gear/utils/index.ts b/ui/src/gear/utils/index.ts new file mode 100644 index 00000000..4fed660f --- /dev/null +++ b/ui/src/gear/utils/index.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; \ No newline at end of file diff --git a/ui/src/gear/utils/lib.ts b/ui/src/gear/utils/lib.ts new file mode 100644 index 00000000..693da49f --- /dev/null +++ b/ui/src/gear/utils/lib.ts @@ -0,0 +1 @@ +export {} \ No newline at end of file diff --git a/ui/src/gear/utils/types.ts b/ui/src/gear/utils/types.ts new file mode 100644 index 00000000..84116f36 --- /dev/null +++ b/ui/src/gear/utils/types.ts @@ -0,0 +1,25 @@ +import { BigIntOrderedMap } from "./BigIntOrderedMap"; + +export type SetElement = S extends Set<(infer T)> ? T : never; +export type MapKey = M extends Map<(infer K), any> ? K : never; +export type MapValue = M extends Map ? V : never; + +/** + * Turns sets into arrays and maps into objects so we can send them over the wire + */ +export type Enc = + S extends Set ? + Enc>[] : + S extends Map ? + { [s: string]: Enc> } : + S extends object ? + { [K in keyof S]: Enc } : + S extends BigIntOrderedMap ? + { [index: string]: T } : + S; + + +export type ShipRank = 'czar' | 'king' | 'duke' | 'earl' | 'pawn'; + +// @uvH encoded string +export type Serial = string; diff --git a/ui/src/global.d.ts b/ui/src/global.d.ts index ce5215a8..ecefe09c 100644 --- a/ui/src/global.d.ts +++ b/ui/src/global.d.ts @@ -1,7 +1,3 @@ -declare module 'urbit-ob' { - export function isValidPatp(patp: string): boolean; -} - type Stringified = string & { [P in keyof T]: { '_ value': T[P] }; diff --git a/ui/src/logic/useSystemUpdate.tsx b/ui/src/logic/useSystemUpdate.tsx index 223f78b2..3ebad797 100644 --- a/ui/src/logic/useSystemUpdate.tsx +++ b/ui/src/logic/useSystemUpdate.tsx @@ -1,4 +1,4 @@ -import { kilnBump, Pike } from '@urbit/api'; +import { kilnBump, Pike } from '@/gear'; import { partition, pick } from 'lodash'; import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; diff --git a/ui/src/logic/utils.ts b/ui/src/logic/utils.ts index 6138b104..7db872ff 100644 --- a/ui/src/logic/utils.ts +++ b/ui/src/logic/utils.ts @@ -1,6 +1,6 @@ import { Yarn, isYarnEmph, isYarnShip } from '@/types/hark'; import { findLast } from 'lodash'; -import { Docket, DocketHref, Treaty } from '@urbit/api'; +import { Docket, DocketHref, Treaty } from '@/gear'; import { hsla, parseToHsla, parseToRgba } from 'color2k'; import _ from 'lodash'; import { differenceInDays, endOfToday, format } from 'date-fns'; @@ -44,13 +44,6 @@ export function handleDropdownLink( }; } -export function deSig(ship: string): string { - if (!ship) { - return ''; - } - return ship.replace('~', ''); -} - export function normalizeUrbitColor(color: string): string { if (color.startsWith('#')) { return color; diff --git a/ui/src/main.tsx b/ui/src/main.tsx index 736b6dad..8444e279 100644 --- a/ui/src/main.tsx +++ b/ui/src/main.tsx @@ -1,4 +1,4 @@ -import { preSig } from '@urbit/api'; +import { preSig } from '@urbit/aura'; import cookies from 'browser-cookies'; import React from 'react'; import ReactDOM from 'react-dom'; diff --git a/ui/src/mocks/mockContacts.ts b/ui/src/mocks/mockContacts.ts index d4a93607..3270acfe 100644 --- a/ui/src/mocks/mockContacts.ts +++ b/ui/src/mocks/mockContacts.ts @@ -1,4 +1,4 @@ -import { Rolodex } from '@urbit/api'; +import { Rolodex } from '@/gear'; const mockContacts: Rolodex = { '~finned-palmer': { diff --git a/ui/src/nav/SystemMenu.tsx b/ui/src/nav/SystemMenu.tsx index 5dd8259a..0884f762 100644 --- a/ui/src/nav/SystemMenu.tsx +++ b/ui/src/nav/SystemMenu.tsx @@ -3,7 +3,7 @@ import classNames from 'classnames'; import clipboardCopy from 'clipboard-copy'; import React, { HTMLAttributes, useCallback, useState } from 'react'; import { Link, Route, useHistory } from 'react-router-dom'; -import { Pike } from '@urbit/api'; +import { Pike } from '@/gear'; import { Adjust } from '../components/icons/Adjust'; import { usePike } from '../state/kiln'; import { disableDefault, handleDropdownLink } from '@/logic/utils'; diff --git a/ui/src/nav/notifications/Notification.tsx b/ui/src/nav/notifications/Notification.tsx index 683d81ba..2808e691 100644 --- a/ui/src/nav/notifications/Notification.tsx +++ b/ui/src/nav/notifications/Notification.tsx @@ -12,7 +12,7 @@ import { ShipName } from '../../components/ShipName'; import { DeskLink } from '../../components/DeskLink'; import { DocketImage } from '../../components/DocketImage'; import GroupAvatar from '../../components/GroupAvatar'; -import { Charge } from '@urbit/api'; +import { Charge } from '@/gear'; import { useSawRopeMutation } from '@/state/hark'; interface NotificationProps { diff --git a/ui/src/nav/search/Apps.tsx b/ui/src/nav/search/Apps.tsx index 7bcb7d64..5b255bf7 100644 --- a/ui/src/nav/search/Apps.tsx +++ b/ui/src/nav/search/Apps.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useEffect, useMemo } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import fuzzy from 'fuzzy'; -import { Treaty } from '@urbit/api'; +import { Treaty } from '@/gear'; import { ShipName } from '../../components/ShipName'; import { useAllyTreaties } from '../../state/docket'; import { useAppSearchStore } from '../Nav'; diff --git a/ui/src/nav/search/Providers.tsx b/ui/src/nav/search/Providers.tsx index f861844c..39748166 100644 --- a/ui/src/nav/search/Providers.tsx +++ b/ui/src/nav/search/Providers.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useMemo } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import fuzzy from 'fuzzy'; -import { Provider, deSig } from '@urbit/api'; -import * as ob from 'urbit-ob'; +import { deSig, isValidPatp } from '@urbit/aura'; +import { Provider } from '@/gear'; import { MatchItem, useAppSearchStore } from '../Nav'; import { useAllies, useCharges } from '../../state/docket'; import { ProviderList } from '../../components/ProviderList'; @@ -59,14 +59,14 @@ export const Providers = ({ match }: ProvidersProps) => { ); const patp = `~${deSig(search) || ''}`; - const isValidPatp = ob.isValidPatp(patp); + const isValid = isValidPatp(patp); const results = useMemo(() => { if (!allies) { return []; } const exact = - isValidPatp && !Object.keys(allies).includes(patp) + isValid && !Object.keys(allies).includes(patp) ? [ { shipName: patp, @@ -109,7 +109,7 @@ export const Providers = ({ match }: ProvidersProps) => { })) : []; - const newProviderMatches = isValidPatp + const newProviderMatches = isValid ? [ { url: `/search/${patp}/apps`, @@ -128,7 +128,7 @@ export const Providers = ({ match }: ProvidersProps) => { ), }); } - }, [results, patp, isValidPatp]); + }, [results, patp, isValid]); return (
= { +const coinFlip = () => Math.random() > 0.5; + +const makeSeal: () => Seal = () => { + return [ + // write perm + { + vane: null, + name: 'write', + hoon: '[%write & %some-agent]', + tail: { + dude: null, + jump: coinFlip() + } + }, + // reads perm + { + vane: null, + name: 'reads', + hoon: '[%reads %g `%u `%settings-store /]', + tail: { + vane: 'gall', + care: 'u', + desk: 'landscape', + spur: '/', + } + } + ] +} + +export const appMetaData: Pick = { cass: { da: '~2021.9.13..05.41.04..ae65', ud: 1 @@ -25,7 +55,9 @@ export const appMetaData: Pick ({ glob: { base } }); @@ -345,7 +377,9 @@ export const mockPikes: Pikes = { sync: null, zest: 'dead', wefts: [], - hash: '0v19.q7u27.omps3.fbhf4.53rai.co157.pben7.pu94n.63v4p.3kcb7.iafj0' + hash: '0v19.q7u27.omps3.fbhf4.53rai.co157.pben7.pu94n.63v4p.3kcb7.iafj0', + perms: [], + lacks: [], }, garden: { sync: { @@ -354,7 +388,9 @@ export const mockPikes: Pikes = { }, zest: 'live', wefts: [], - hash: '0v18.hbbs6.onu15.skjkv.qrfgl.vf4oo.0igo5.2q0d3.6r3r8.2dkmo.oa04m' + hash: '0v18.hbbs6.onu15.skjkv.qrfgl.vf4oo.0igo5.2q0d3.6r3r8.2dkmo.oa04m', + perms: [], + lacks: [], }, landscape: { sync: { @@ -363,12 +399,16 @@ export const mockPikes: Pikes = { }, zest: 'live', wefts: [], - hash: '0v1t.qln8k.cskmt.cn6lv.gu335.jfba6.kte90.iqqn3.aj67b.t389a.8imuo' + hash: '0v1t.qln8k.cskmt.cn6lv.gu335.jfba6.kte90.iqqn3.aj67b.t389a.8imuo', + perms: [], + lacks: [], }, base: { sync: null, zest: 'live', wefts: [], - hash: '0v1e.b5auh.6u82i.hqk1r.22kli.4ubef.a1cbo.3g532.6l49k.g0i8e.t6eid' + hash: '0v1e.b5auh.6u82i.hqk1r.22kli.4ubef.a1cbo.3g532.6l49k.g0i8e.t6eid', + perms: [], + lacks: [], } }; diff --git a/ui/src/state/settings.ts b/ui/src/state/settings.ts index eb6cca64..caac3eb3 100644 --- a/ui/src/state/settings.ts +++ b/ui/src/state/settings.ts @@ -1,5 +1,5 @@ /* eslint-disable no-param-reassign */ -import { DelBucket, DelEntry, PutBucket, Value } from '@urbit/api'; +import { DelBucket, DelEntry, PutBucket, Value } from '@/gear'; import _ from 'lodash'; import api from '../api'; import useReactQuerySubscription from '@/logic/useReactQuerySubscription'; @@ -8,7 +8,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import produce from 'immer'; interface PutEntry { - // this is defined here because the PutEntry type in @urbit/api is missing the desk field + // this is defined here because the PutEntry type in @/gear is missing the desk field 'put-entry': { 'bucket-key': string; 'entry-key': string; diff --git a/ui/src/state/storage/index.ts b/ui/src/state/storage/index.ts index 430ee8ce..6f714fc6 100644 --- a/ui/src/state/storage/index.ts +++ b/ui/src/state/storage/index.ts @@ -7,7 +7,7 @@ import { reduceStateN, BaseState, } from '../base'; -import { S3Credentials } from '@urbit/api'; +import { StorageCredentials } from '@/gear'; enableMapSet(); @@ -22,7 +22,7 @@ export interface BaseStorageState { currentBucket: string; region: string; }; - credentials: S3Credentials | null; + credentials: StorageCredentials | null; }; [ref: string]: unknown; } diff --git a/ui/src/state/storage/reducer.ts b/ui/src/state/storage/reducer.ts index d75f7345..9f5ffadc 100644 --- a/ui/src/state/storage/reducer.ts +++ b/ui/src/state/storage/reducer.ts @@ -1,11 +1,11 @@ -import { S3Update } from '@urbit/api'; +import { StorageUpdate } from '@/gear'; import _ from 'lodash'; import { BaseState } from '../base'; import { StorageState as State } from '.'; type StorageState = State & BaseState; -const credentials = (json: S3Update, state: StorageState): StorageState => { +const credentials = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'credentials', false); if (data) { state.s3.credentials = data; @@ -13,7 +13,7 @@ const credentials = (json: S3Update, state: StorageState): StorageState => { return state; }; -const configuration = (json: S3Update, state: StorageState): StorageState => { +const configuration = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'configuration', false); if (data) { state.s3.configuration = { @@ -25,7 +25,7 @@ const configuration = (json: S3Update, state: StorageState): StorageState => { return state; }; -const currentBucket = (json: S3Update, state: StorageState): StorageState => { +const currentBucket = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'setCurrentBucket', false); if (data && state.s3) { state.s3.configuration.currentBucket = data; @@ -33,7 +33,7 @@ const currentBucket = (json: S3Update, state: StorageState): StorageState => { return state; }; -const region = (json: S3Update, state: StorageState): StorageState => { +const region = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'setRegion', false); if (data && state.s3) { state.s3.configuration.region = data; @@ -41,7 +41,7 @@ const region = (json: S3Update, state: StorageState): StorageState => { return state; }; -const addBucket = (json: S3Update, state: StorageState): StorageState => { +const addBucket = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'addBucket', false); if (data) { state.s3.configuration.buckets = state.s3.configuration.buckets.add(data); @@ -49,7 +49,7 @@ const addBucket = (json: S3Update, state: StorageState): StorageState => { return state; }; -const removeBucket = (json: S3Update, state: StorageState): StorageState => { +const removeBucket = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'removeBucket', false); if (data) { state.s3.configuration.buckets.delete(data); @@ -57,7 +57,7 @@ const removeBucket = (json: S3Update, state: StorageState): StorageState => { return state; }; -const endpoint = (json: S3Update, state: StorageState): StorageState => { +const endpoint = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'setEndpoint', false); if (data && state.s3.credentials) { state.s3.credentials.endpoint = data; @@ -65,7 +65,7 @@ const endpoint = (json: S3Update, state: StorageState): StorageState => { return state; }; -const accessKeyId = (json: S3Update, state: StorageState): StorageState => { +const accessKeyId = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'setAccessKeyId', false); if (data && state.s3.credentials) { state.s3.credentials.accessKeyId = data; @@ -73,7 +73,7 @@ const accessKeyId = (json: S3Update, state: StorageState): StorageState => { return state; }; -const secretAccessKey = (json: S3Update, state: StorageState): StorageState => { +const secretAccessKey = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'setSecretAccessKey', false); if (data && state.s3.credentials) { state.s3.credentials.secretAccessKey = data; diff --git a/ui/src/tiles/Tile.tsx b/ui/src/tiles/Tile.tsx index e9d5848f..2fcce08d 100644 --- a/ui/src/tiles/Tile.tsx +++ b/ui/src/tiles/Tile.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import React, { FunctionComponent } from 'react'; import { useDrag } from 'react-dnd'; -import { chadIsRunning } from '@urbit/api'; +import { chadIsRunning } from '@/gear'; import { TileMenu } from './TileMenu'; import { Spinner } from '../components/Spinner'; import { getAppHref } from '@/logic/utils'; diff --git a/ui/src/tiles/TileMenu.tsx b/ui/src/tiles/TileMenu.tsx index bd6d1f90..2df238aa 100644 --- a/ui/src/tiles/TileMenu.tsx +++ b/ui/src/tiles/TileMenu.tsx @@ -2,7 +2,7 @@ import React, { ReactElement, useCallback, useState } from 'react'; import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import classNames from 'classnames'; import { Link } from 'react-router-dom'; -import { Chad, chadIsRunning } from '@urbit/api'; +import { Chad, chadIsRunning } from '@/gear'; import useDocketState from '../state/docket'; import { disableDefault, handleDropdownLink } from '@/logic/utils'; import { useMedia } from '../logic/useMedia';