diff --git a/pkg/arvo/app/group-view.hoon b/pkg/arvo/app/group-view.hoon index 4f2a3d690..e7b2177b0 100644 --- a/pkg/arvo/app/group-view.hoon +++ b/pkg/arvo/app/group-view.hoon @@ -193,6 +193,11 @@ (~(put by joining) rid [%.n now.bowl ship %start]) =. jn-core (jn-abed rid) + =. jn-core + %- emit + %+ fact:io + group-view-update+!>([%started rid (~(got by joining) rid)]) + ~[/all] ?< ~|("already joined {}" (has-joined rid)) =. jn-core %- emit diff --git a/pkg/arvo/lib/group-view.hoon b/pkg/arvo/lib/group-view.hoon index 3a593d975..9341243ae 100644 --- a/pkg/arvo/lib/group-view.hoon +++ b/pkg/arvo/lib/group-view.hoon @@ -54,9 +54,17 @@ ?- -.upd %initial (initial +.upd) %progress (progress +.upd) + %started (started +.upd) %hide s+(enjs-path:resource +.upd) == :: + ++ started + |= [rid=resource req=^request] + %- pairs + :~ resource+s+(enjs-path:resource rid) + request+(request req) + == + :: ++ progress |= [rid=resource prog=^progress] %- pairs diff --git a/pkg/arvo/mar/graph/validator/link.hoon b/pkg/arvo/mar/graph/validator/link.hoon index e613adc98..819af49bb 100644 --- a/pkg/arvo/mar/graph/validator/link.hoon +++ b/pkg/arvo/mar/graph/validator/link.hoon @@ -52,7 +52,7 @@ :: top-level link post; title and url :: [@ ~] - ?> ?=([[%text @] [%url @] ~] contents.p.ip) + ?> ?=([[%text @] $%([%url @] [%reference *]) ~] contents.p.ip) ip :: :: comment on link post; container structure diff --git a/pkg/arvo/mar/graph/validator/post.hoon b/pkg/arvo/mar/graph/validator/post.hoon index 930a5e9fa..ec9c1a20f 100644 --- a/pkg/arvo/mar/graph/validator/post.hoon +++ b/pkg/arvo/mar/graph/validator/post.hoon @@ -12,10 +12,11 @@ ++ graph-permissions-remove |= vip=vip-metadata:met [%yes %self %self] - :: +notification-kind: no notifications for now + :: +notification-kind: don't track unreads, notify on replies :: ++ notification-kind =/ len (lent index.p.i) + ?: =(1 len) ~ `[%post [(dec len) len] %none %children] :: ++ transform-add-nodes diff --git a/pkg/arvo/sur/group-view.hoon b/pkg/arvo/sur/group-view.hoon index 86b2ee689..82a0a51a4 100644 --- a/pkg/arvo/sur/group-view.hoon +++ b/pkg/arvo/sur/group-view.hoon @@ -31,6 +31,7 @@ :: +$ update $% [%initial initial=(map resource request)] + [%started =resource =request] [%progress =resource =progress] [%hide =resource] == diff --git a/pkg/interface/src/logic/api/graph.ts b/pkg/interface/src/logic/api/graph.ts index e171a05c3..bddf17943 100644 --- a/pkg/interface/src/logic/api/graph.ts +++ b/pkg/interface/src/logic/api/graph.ts @@ -308,10 +308,8 @@ export default class GraphApi extends BaseApi { } getGraph(ship: string, resource: string) { - console.log(ship, resource); return this.scry('graph-store', `/graph/${ship}/${resource}`) .then((graph) => { - console.log(graph); this.store.handleEvent({ data: graph }); diff --git a/pkg/interface/src/logic/reducers/group-view.ts b/pkg/interface/src/logic/reducers/group-view.ts index 816a313b9..518da6c6f 100644 --- a/pkg/interface/src/logic/reducers/group-view.ts +++ b/pkg/interface/src/logic/reducers/group-view.ts @@ -11,12 +11,22 @@ const initial = (json: any, state: GroupState): GroupState => { return state; }; +const started = (json: any, state: GroupState): GroupState => { + const data = json.started; + if(data) { + const { resource, request } = data; + state.pendingJoin[resource] = request; + } + return state; +} + const progress = (json: any, state: GroupState): GroupState => { const data = json.progress; if(data) { const { progress, resource } = data; state.pendingJoin[resource].progress = progress; if(progress === 'done') { + setTimeout(() => { delete state.pendingJoin[resource]; }, 10000); @@ -40,6 +50,7 @@ export const GroupViewReducer = (json: any) => { reduceState(useGroupState, data, [ progress, hide, + started, initial ]); } diff --git a/pkg/interface/src/views/apps/chat/components/chat-editor.js b/pkg/interface/src/views/apps/chat/components/chat-editor.js index 4e0611e89..c52243363 100644 --- a/pkg/interface/src/views/apps/chat/components/chat-editor.js +++ b/pkg/interface/src/views/apps/chat/components/chat-editor.js @@ -144,7 +144,6 @@ export default class ChatEditor extends Component { messageChange(editor, data, value) { if(value.endsWith('/')) { - console.log('showing'); editor.showHint(['test', 'foo']); } if (this.state.message !== '' && value == '') { diff --git a/pkg/interface/src/views/apps/links/components/LinkItem.tsx b/pkg/interface/src/views/apps/links/components/LinkItem.tsx index 5f7705c66..a3e206543 100644 --- a/pkg/interface/src/views/apps/links/components/LinkItem.tsx +++ b/pkg/interface/src/views/apps/links/components/LinkItem.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useRef, useCallback, ReactElement } from 'react'; import { Link } from 'react-router-dom'; -import { Row, Col, Anchor, Box, Text, Icon, Action } from '@tlon/indigo-react'; +import { Row, Col, Anchor, Box, Text, Icon, Action, Rule } from '@tlon/indigo-react'; import { GraphNode, Group, Rolodex, Unreads, Association } from '@urbit/api'; import { writeText } from '~/logic/lib/util'; @@ -12,7 +12,8 @@ import { Dropdown } from '~/views/components/Dropdown'; import RemoteContent from '~/views/components/RemoteContent'; import useHarkState from '~/logic/state/hark'; import {useCopy} from '~/logic/lib/useCopy'; -import {usePermalinkForGraph, getPermalinkForGraph} from '~/logic/lib/permalinks'; +import {usePermalinkForGraph, getPermalinkForGraph, referenceToPermalink} from '~/logic/lib/permalinks'; +import {PermalinkEmbed} from '../../permalinks/embed'; interface LinkItemProps { node: GraphNode; @@ -78,11 +79,12 @@ export const LinkItem = (props: LinkItemProps): ReactElement => { const { doCopy: doCopyLink, copyDisplay: locationText } = useCopy( contents[1].url, - 'Copy Link Location' + 'Copy block source' ); + const { doCopy: doCopyNode, copyDisplay: nodeText } = useCopy( permalink, - 'Copy Node Permalink' + 'Copy reference' ); const deleteLink = () => { @@ -119,6 +121,13 @@ export const LinkItem = (props: LinkItemProps): ReactElement => { onClick={markRead} > {contents[0].text} + { 'reference' in contents[1] ? ( + <> + + + + ) : ( + <> { remoteRef.current = r }} renderUrl={false} @@ -146,12 +155,14 @@ export const LinkItem = (props: LinkItemProps): ReactElement => { }} /> - - - {hostname} - - - + + + {hostname} + + + + + )} { const doPost = () => { const url = linkValue; const text = linkTitle ? linkTitle : linkValue; + const contents = url.startsWith('web+urbitgraph:/') + ? [{ text }, permalinkToReference(parsePermalink(url)!) ] + : [{ text }, { url }]; + setDisabled(true); const parentIndex = props.parentIndex || ''; - const post = createPost([ - { text }, - { url } - ], parentIndex); + const post = createPost(contents, parentIndex); props.api.graph.addPost( `~${props.ship}`, @@ -61,6 +63,13 @@ const LinkSubmit = (props: LinkSubmitProps) => { setLinkValue(link); } } + if(link.startsWith('web+urbitgraph://')) { + const permalink = parsePermalink(link); + if(!permalink) { + setLinkValid(false); + return; + } + } if (linkValid) { if (hasProvider(linkValue)) { diff --git a/pkg/interface/src/views/apps/notifications/graph.tsx b/pkg/interface/src/views/apps/notifications/graph.tsx index 700c44a67..7171f59e2 100644 --- a/pkg/interface/src/views/apps/notifications/graph.tsx +++ b/pkg/interface/src/views/apps/notifications/graph.tsx @@ -21,6 +21,8 @@ import ChatMessage from '../chat/components/ChatMessage'; import useContactState from '~/logic/state/contact'; import useGroupState from '~/logic/state/group'; import useMetadataState from '~/logic/state/metadata'; +import {PermalinkEmbed} from '../permalinks/embed'; +import {parsePermalink, referenceToPermalink} from '~/logic/lib/permalinks'; function getGraphModuleIcon(module: string) { if (module === 'link') { @@ -63,14 +65,27 @@ function describeNotification(description: string, plural: boolean): string { } } -const GraphUrl = ({ url, title }) => ( - - - - {title} - - -); +const GraphUrl = ({ contents, api }) => { + const [{ text }, link] = contents; + + + if('reference' in link) { + return ( + ); + } + return ( + + + + {text} + + + ); +} export const GraphNodeContent = ({ group, @@ -83,8 +98,7 @@ export const GraphNodeContent = ({ const idx = index.slice(1).split('/'); if (mod === 'link') { if (idx.length === 1) { - const [{ text }, { url }] = contents; - return ; + return ; } else if (idx.length === 3) { return ; } @@ -172,7 +186,7 @@ function getNodeUrl( return `${graphUrl}/note/${noteId}`; } else if (mod === 'link') { const [linkId] = idx; - return `${graphUrl}/${linkId}`; + return `${graphUrl}/index/${linkId}`; } else if (mod === 'chat') { if(idx.length > 0) { return `${graphUrl}?msg=${idx[0]}`; diff --git a/pkg/interface/src/views/apps/notifications/invites.tsx b/pkg/interface/src/views/apps/notifications/invites.tsx index 194e594fe..7b9f04e70 100644 --- a/pkg/interface/src/views/apps/notifications/invites.tsx +++ b/pkg/interface/src/views/apps/notifications/invites.tsx @@ -89,6 +89,7 @@ export function Invites(props: InvitesProps): ReactElement { invite={invite} app={app} uid={uid} + join={join} resource={resource} /> ); diff --git a/pkg/interface/src/views/apps/notifications/notifications.tsx b/pkg/interface/src/views/apps/notifications/notifications.tsx index 8e27240c2..1e801b538 100644 --- a/pkg/interface/src/views/apps/notifications/notifications.tsx +++ b/pkg/interface/src/views/apps/notifications/notifications.tsx @@ -14,6 +14,7 @@ import GroupSearch from '~/views/components/GroupSearch'; import { useTutorialModal } from '~/views/components/useTutorialModal'; import useHarkState from '~/logic/state/hark'; import useMetadataState from '~/logic/state/metadata'; +import useGroupState from '~/logic/state/group'; const baseUrl = '/~notifications'; @@ -41,6 +42,7 @@ export default function NotificationsScreen(props: any): ReactElement { const [filter, setFilter] = useState({ groups: [] }); const associations = useMetadataState(state => state.associations); + const pendingJoin = useGroupState(s => s.pendingJoin); const onSubmit = async ({ groups } : NotificationFilter) => { setFilter({ groups }); }; @@ -128,7 +130,11 @@ export default function NotificationsScreen(props: any): ReactElement { - {!view && } + {!view && } diff --git a/pkg/interface/src/views/apps/permalinks/TranscludedNode.tsx b/pkg/interface/src/views/apps/permalinks/TranscludedNode.tsx index 071afac64..67b1e4374 100644 --- a/pkg/interface/src/views/apps/permalinks/TranscludedNode.tsx +++ b/pkg/interface/src/views/apps/permalinks/TranscludedNode.tsx @@ -1,15 +1,18 @@ import React from "react"; import { Anchor, Icon, Box, Row, Col, Text } from "@tlon/indigo-react"; import ChatMessage from "../chat/components/ChatMessage"; -import { Association, GraphNode } from "@urbit/api"; +import { Association, GraphNode, Post, Group } from "@urbit/api"; import { useGroupForAssoc } from "~/logic/state/group"; import { MentionText } from "~/views/components/MentionText"; import Author from "~/views/components/Author"; import { NoteContent } from "../publish/components/Note"; +import { PostContent } from "~/views/landscape/components/Home/Post/PostContent"; import bigInt from "big-integer"; import { getSnippet } from "~/logic/lib/publish"; import { NotePreviewContent } from "../publish/components/NotePreview"; import GlobalApi from "~/logic/api/global"; +import {PermalinkEmbed} from "./embed"; +import {referenceToPermalink} from "~/logic/lib/permalinks"; function TranscludedLinkNode(props: { node: GraphNode; @@ -22,10 +25,16 @@ function TranscludedLinkNode(props: { switch (idx.length) { case 1: - const [{ text }, { url }] = node.post.contents; + const [{ text }, link] = node.post.contents; + if('reference' in link) { + const permalink = referenceToPermalink(link).link; + return + + } + return ( - + {text} @@ -124,6 +133,34 @@ function TranscludedPublishNode(props: { } } +export function TranscludedPost(props: { + post: Post; + api: GlobalApi; + transcluded: number; + group: Group; +}) { + const { transcluded, post, group, api } = props; + return ( + + + + + + + ); +} + export function TranscludedNode(props: { assoc: Association; node: GraphNode; @@ -158,6 +195,15 @@ export function TranscludedNode(props: { return ; case "link": return ; + case "post": + return ( + ) + ; default: return null; } diff --git a/pkg/interface/src/views/apps/permalinks/app.tsx b/pkg/interface/src/views/apps/permalinks/app.tsx index 2db2d3646..20f088738 100644 --- a/pkg/interface/src/views/apps/permalinks/app.tsx +++ b/pkg/interface/src/views/apps/permalinks/app.tsx @@ -29,13 +29,11 @@ export function PermalinkRoutes(props: {}) { path="/perma/group/:ship/:name" render={({ match, history, location }) => { const { ship, name } = match.params as ResourceRouteProps; - console.log(ship); const { url } = match; const path = `/ship/${ship}/${name}`; const group = groups[path]; if(!group) { if (Object.keys(groups).length > 0) { - console.log(groups); const redir = location.pathname; const to = toQuery({ redir }, `/~landscape/join/${ship}/${name}`); return ; @@ -60,7 +58,6 @@ function FallbackRoutes(props: { query: URLSearchParams }) { return ; } - console.log('aaaaa'); return ; } @@ -71,7 +68,6 @@ function GroupRoutes(props: { group: string; url: string }) { const graphKeys = useGraphState(s => s.graphKeys); const { toQuery } = useQuery(); const groupUrl = `/~landscape${group}`; - console.log(group); return ( @@ -85,7 +81,6 @@ function GroupRoutes(props: { group: string; url: string }) { if(!association) { return null; } - console.log(graphKeys); if(!graphKeys.has(`${ship.slice(1)}/${name}`)) { if(graphKeys.size > 0) { return s.looseNodes?.[`${ship.slice(1)}/${name}`]?.[index], [ @@ -79,10 +80,9 @@ function GraphPermalink( return ( { e.stopPropagation(); }} @@ -161,6 +161,7 @@ export function PermalinkEmbed(props: { api: GlobalApi; transcluded: number; showOurContact?: boolean; + full?: boolean; }) { const permalink = parsePermalink(props.link); @@ -177,6 +178,7 @@ export function PermalinkEmbed(props: { transcluded={props.transcluded} {...permalink} api={props.api} + full={props.full} showOurContact={props.showOurContact} /> ); diff --git a/pkg/interface/src/views/components/Invite/index.tsx b/pkg/interface/src/views/components/Invite/index.tsx index a316a3d0b..a8d90f781 100644 --- a/pkg/interface/src/views/components/Invite/index.tsx +++ b/pkg/interface/src/views/components/Invite/index.tsx @@ -108,7 +108,7 @@ export function InviteItem(props: InviteItemProps) { } }, [invite]); - if(status?.hidden) { + if(pendingJoin?.hidden) { return null; } @@ -119,7 +119,7 @@ export function InviteItem(props: InviteItemProps) { api={api} preview={preview} invite={invite} - status={status} + status={pendingJoin} {...handlers} /> ); diff --git a/pkg/interface/src/views/landscape/components/Home/Post/PostItem/PostContent.js b/pkg/interface/src/views/landscape/components/Home/Post/PostItem/PostContent.js index 7c3996879..6644029a3 100644 --- a/pkg/interface/src/views/landscape/components/Home/Post/PostItem/PostContent.js +++ b/pkg/interface/src/views/landscape/components/Home/Post/PostItem/PostContent.js @@ -19,6 +19,7 @@ export function PostContent(props) { contacts={contacts} content={post.contents} api={api} + transcluded={0} /> );