mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-11-11 04:48:00 +03:00
Merge branch 'release/next-userspace' into la/feed-perf
This commit is contained in:
commit
bf49fd81f9
@ -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 {<rid>}" (has-joined rid))
|
||||
=. jn-core
|
||||
%- emit
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -31,6 +31,7 @@
|
||||
::
|
||||
+$ update
|
||||
$% [%initial initial=(map resource request)]
|
||||
[%started =resource =request]
|
||||
[%progress =resource =progress]
|
||||
[%hide =resource]
|
||||
==
|
||||
|
@ -308,10 +308,8 @@ export default class GraphApi extends BaseApi<StoreState> {
|
||||
}
|
||||
|
||||
getGraph(ship: string, resource: string) {
|
||||
console.log(ship, resource);
|
||||
return this.scry<any>('graph-store', `/graph/${ship}/${resource}`)
|
||||
.then((graph) => {
|
||||
console.log(graph);
|
||||
this.store.handleEvent({
|
||||
data: graph
|
||||
});
|
||||
|
@ -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<GroupState, GroupUpdate>(useGroupState, data, [
|
||||
progress,
|
||||
hide,
|
||||
started,
|
||||
initial
|
||||
]);
|
||||
}
|
||||
|
@ -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 == '') {
|
||||
|
@ -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}
|
||||
>
|
||||
<Text p={2}>{contents[0].text}</Text>
|
||||
{ 'reference' in contents[1] ? (
|
||||
<>
|
||||
<Rule />
|
||||
<PermalinkEmbed full link={referenceToPermalink(contents[1]).link} api={api} transcluded={0} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<RemoteContent
|
||||
ref={r => { remoteRef.current = r }}
|
||||
renderUrl={false}
|
||||
@ -152,6 +161,8 @@ export const LinkItem = (props: LinkItemProps): ReactElement => {
|
||||
</Box>
|
||||
</Anchor>
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
<Row minWidth='0' flexShrink={0} width="100%" justifyContent="space-between" py={3} bg="white">
|
||||
<Author
|
||||
|
@ -7,6 +7,7 @@ import { StorageState } from '~/types';
|
||||
import SubmitDragger from '~/views/components/SubmitDragger';
|
||||
import { createPost } from '~/logic/api/graph';
|
||||
import { hasProvider } from 'oembed-parser';
|
||||
import {parsePermalink, permalinkToReference} from '~/logic/lib/permalinks';
|
||||
|
||||
interface LinkSubmitProps {
|
||||
api: GlobalApi;
|
||||
@ -28,12 +29,13 @@ const LinkSubmit = (props: LinkSubmitProps) => {
|
||||
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)) {
|
||||
|
@ -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 }) => (
|
||||
const GraphUrl = ({ contents, api }) => {
|
||||
const [{ text }, link] = contents;
|
||||
|
||||
|
||||
if('reference' in link) {
|
||||
return (
|
||||
<PermalinkEmbed
|
||||
transcluded={1}
|
||||
link={referenceToPermalink(link).link}
|
||||
api={api}
|
||||
/>);
|
||||
}
|
||||
return (
|
||||
<Box borderRadius='2' p='2' bg='scales.black05'>
|
||||
<Anchor underline={false} target='_blank' color='black' href={url}>
|
||||
<Anchor underline={false} target='_blank' color='black' href={link.url}>
|
||||
<Icon verticalAlign='bottom' mr='2' icon='ArrowExternal' />
|
||||
{title}
|
||||
{text}
|
||||
</Anchor>
|
||||
</Box>
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
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 <GraphUrl title={text} url={url} />;
|
||||
return <GraphUrl contents={contents} />;
|
||||
} else if (idx.length === 3) {
|
||||
return <MentionText content={contents} group={group} />;
|
||||
}
|
||||
@ -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]}`;
|
||||
|
@ -89,6 +89,7 @@ export function Invites(props: InvitesProps): ReactElement {
|
||||
invite={invite}
|
||||
app={app}
|
||||
uid={uid}
|
||||
join={join}
|
||||
resource={resource}
|
||||
/>
|
||||
);
|
||||
|
@ -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<NotificationFilter>({ 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 {
|
||||
</Dropdown>
|
||||
</Row>
|
||||
</Row>
|
||||
{!view && <Inbox {...props} filter={filter.groups} />}
|
||||
{!view && <Inbox
|
||||
pendingJoin={pendingJoin}
|
||||
{...props}
|
||||
filter={filter.groups}
|
||||
/>}
|
||||
</Col>
|
||||
</Body>
|
||||
</>
|
||||
|
@ -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 <PermalinkEmbed transcluded={transcluded + 1} api={api} link={permalink} association={assoc} />
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<Box borderRadius="2" p="2" bg="scales.black05">
|
||||
<Anchor underline={false} target="_blank" color="black" href={url}>
|
||||
<Anchor underline={false} target="_blank" color="black" href={link.url}>
|
||||
<Icon verticalAlign="bottom" mr="2" icon="ArrowExternal" />
|
||||
{text}
|
||||
</Anchor>
|
||||
@ -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 (
|
||||
<Col>
|
||||
<Author
|
||||
p="2"
|
||||
showImage
|
||||
ship={post.author}
|
||||
date={post?.["time-sent"]}
|
||||
group={group}
|
||||
/>
|
||||
<Box p="2">
|
||||
<MentionText
|
||||
api={api}
|
||||
transcluded={transcluded}
|
||||
content={post.contents}
|
||||
group={group}
|
||||
/>
|
||||
</Box>
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
|
||||
export function TranscludedNode(props: {
|
||||
assoc: Association;
|
||||
node: GraphNode;
|
||||
@ -158,6 +195,15 @@ export function TranscludedNode(props: {
|
||||
return <TranscludedPublishNode {...props} />;
|
||||
case "link":
|
||||
return <TranscludedLinkNode {...props} />;
|
||||
case "post":
|
||||
return (
|
||||
<TranscludedPost
|
||||
api={props.api}
|
||||
post={node.post}
|
||||
group={group}
|
||||
transcluded={transcluded}
|
||||
/>)
|
||||
;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -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 <Redirect to={to} />;
|
||||
@ -60,7 +58,6 @@ function FallbackRoutes(props: { query: URLSearchParams }) {
|
||||
return <Redirect to={{ pathname: url }} />;
|
||||
}
|
||||
|
||||
console.log('aaaaa');
|
||||
return <Redirect to="/~404" />;
|
||||
}
|
||||
|
||||
@ -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 (
|
||||
<Switch>
|
||||
@ -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 <Redirect
|
||||
|
@ -44,9 +44,10 @@ function GraphPermalink(
|
||||
transcluded: number;
|
||||
pending?: boolean;
|
||||
showOurContact?: boolean;
|
||||
full?: boolean;
|
||||
}
|
||||
) {
|
||||
const { showOurContact, pending, link, graph, group, index, api, transcluded } = props;
|
||||
const { full = false, showOurContact, pending, link, graph, group, index, api, transcluded } = props;
|
||||
const { ship, name } = resourceFromPath(graph);
|
||||
const node = useGraphState(
|
||||
useCallback((s) => s.looseNodes?.[`${ship.slice(1)}/${name}`]?.[index], [
|
||||
@ -79,10 +80,9 @@ function GraphPermalink(
|
||||
return (
|
||||
<Col
|
||||
width="100%"
|
||||
my="1"
|
||||
bg="white"
|
||||
maxWidth="500px"
|
||||
border="1"
|
||||
maxWidth={full ? null : "500px"}
|
||||
border={full ? null : "1"}
|
||||
borderColor="lightGray"
|
||||
borderRadius="2"
|
||||
onClick={(e) => { 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}
|
||||
/>
|
||||
);
|
||||
|
@ -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}
|
||||
/>
|
||||
);
|
||||
|
@ -19,6 +19,7 @@ export function PostContent(props) {
|
||||
contacts={contacts}
|
||||
content={post.contents}
|
||||
api={api}
|
||||
transcluded={0}
|
||||
/>
|
||||
</Col>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user