mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-11-11 04:48:00 +03:00
post: refactor routes
This commit is contained in:
parent
405e55dce2
commit
90c9c2ee87
27
pkg/interface/src/logic/lib/graph.ts
Normal file
27
pkg/interface/src/logic/lib/graph.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { Graph } from '@urbit/api';
|
||||
import { BigInteger } from 'big-integer';
|
||||
import _ from 'lodash';
|
||||
import useMetadataState from '~/logic/state/metadata';
|
||||
|
||||
export function getNodeFromGraph(graph: Graph, index: BigInteger[]) {
|
||||
return _.reduce(
|
||||
index.slice(1),
|
||||
(acc, val) => {
|
||||
return acc?.children?.get(val);
|
||||
},
|
||||
graph.get(index[0])
|
||||
);
|
||||
}
|
||||
|
||||
export function getPostRoute(
|
||||
graph: string,
|
||||
index: BigInteger[],
|
||||
thread = false
|
||||
) {
|
||||
const association = useMetadataState.getState().associations.graph[graph];
|
||||
const segment = thread ? 'thread' : 'replies';
|
||||
|
||||
return `/~landscape${association.group}/feed/${segment}/${index
|
||||
.map(i => i.toString())
|
||||
.join('/')}`;
|
||||
}
|
@ -10,7 +10,7 @@ import useGroupState from '~/logic/state/group';
|
||||
import useMetadataState from '~/logic/state/metadata';
|
||||
import { Loading } from '~/views/components/Loading';
|
||||
import { GroupFeedHeader } from './GroupFeedHeader';
|
||||
import PostReplies from './Post/PostReplies';
|
||||
import { PostRepliesRoutes } from './Post/PostReplies';
|
||||
import PostTimeline from './Post/PostTimeline';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
@ -41,7 +41,6 @@ function GroupFeed(props) {
|
||||
const association = associations.graph[graphPath];
|
||||
|
||||
const history = useHistory();
|
||||
const locationUrl = history.location.pathname;
|
||||
|
||||
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
|
||||
const graph = graphs[graphId];
|
||||
@ -76,42 +75,26 @@ function GroupFeed(props) {
|
||||
graphResource={graphResource}
|
||||
/>
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path={[relativePath('/'), relativePath('/feed')]}
|
||||
render={(routeProps) => {
|
||||
return (
|
||||
<PostTimeline
|
||||
baseUrl={baseUrl}
|
||||
history={history}
|
||||
graphPath={graphPath}
|
||||
group={group}
|
||||
association={association}
|
||||
vip={vip}
|
||||
graph={graph}
|
||||
pendingSize={pendingSize}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
path={relativePath('/feed/replies/:index+')}
|
||||
render={(routeProps) => {
|
||||
return (
|
||||
<PostReplies
|
||||
locationUrl={locationUrl}
|
||||
baseUrl={baseUrl}
|
||||
history={history}
|
||||
graphPath={graphPath}
|
||||
group={group}
|
||||
association={association}
|
||||
vip={vip}
|
||||
graph={graph}
|
||||
pendingSize={pendingSize}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route exact path={relativePath('/feed')}>
|
||||
<PostTimeline
|
||||
baseUrl={relativePath('/feed')}
|
||||
history={history}
|
||||
graphPath={graphPath}
|
||||
group={group}
|
||||
association={association}
|
||||
vip={vip}
|
||||
graph={graph}
|
||||
pendingSize={pendingSize}
|
||||
/>
|
||||
</Route>
|
||||
<Route path={relativePath('/feed/replies')}>
|
||||
<PostRepliesRoutes
|
||||
baseUrl={relativePath('/feed/replies')}
|
||||
association={association}
|
||||
vip={vip}
|
||||
pendingSize={pendingSize}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
</Col>
|
||||
);
|
||||
|
@ -9,11 +9,11 @@ import { useGroup } from '~/logic/state/group';
|
||||
import { useAssocForGraph } from '~/logic/state/metadata';
|
||||
import { Loading } from '~/views/components/Loading';
|
||||
import { GroupFeedHeader } from './GroupFeedHeader';
|
||||
import PostThread from './Post/PostThread';
|
||||
import { PostThreadRoutes } from './Post/PostThread';
|
||||
import PostFlatTimeline from './Post/PostFlatTimeline';
|
||||
import PostReplies from './Post/PostReplies';
|
||||
import airlock from '~/logic/api';
|
||||
import { markCountAsRead } from '@urbit/api';
|
||||
import { PostRepliesRoutes } from './Post/PostReplies';
|
||||
|
||||
function GroupFlatFeed(props) {
|
||||
const {
|
||||
@ -35,7 +35,6 @@ function GroupFlatFeed(props) {
|
||||
|
||||
const relativePath = path => baseUrl + path;
|
||||
const history = useHistory();
|
||||
const locationUrl = history.location.pathname;
|
||||
const getDeepOlderThan = useGraphState(s => s.getDeepOlderThan);
|
||||
|
||||
useEffect(() => {
|
||||
@ -67,56 +66,32 @@ function GroupFlatFeed(props) {
|
||||
graphResource={graphRid}
|
||||
/>
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path={[relativePath('/'), relativePath('/feed')]}
|
||||
render={(routeProps) => {
|
||||
return (
|
||||
<PostFlatTimeline
|
||||
baseUrl={baseUrl}
|
||||
graphPath={graphPath}
|
||||
group={group}
|
||||
association={association}
|
||||
vip={vip}
|
||||
pendingSize={pendingSize}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
path={relativePath('/feed/thread/:index+')}
|
||||
render={(routeProps) => {
|
||||
return (
|
||||
<PostThread
|
||||
locationUrl={locationUrl}
|
||||
baseUrl={baseUrl}
|
||||
history={history}
|
||||
graphPath={graphPath}
|
||||
group={group}
|
||||
association={association}
|
||||
vip={vip}
|
||||
pendingSize={pendingSize}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
path={relativePath('/feed/replies/:index+')}
|
||||
render={(routeProps) => {
|
||||
return (
|
||||
<PostReplies
|
||||
locationUrl={locationUrl}
|
||||
baseUrl={baseUrl}
|
||||
history={history}
|
||||
graphPath={graphPath}
|
||||
group={group}
|
||||
association={association}
|
||||
vip={vip}
|
||||
pendingSize={pendingSize}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route exact path={[relativePath('/'), relativePath('/feed')]}>
|
||||
<PostFlatTimeline
|
||||
baseUrl={relativePath('/feed')}
|
||||
graphPath={graphPath}
|
||||
group={group}
|
||||
association={association}
|
||||
vip={vip}
|
||||
pendingSize={pendingSize}
|
||||
/>
|
||||
</Route>
|
||||
<Route path={relativePath('/feed/thread')}>
|
||||
<PostThreadRoutes
|
||||
baseUrl={relativePath('/feed/thread')}
|
||||
association={association}
|
||||
vip={vip}
|
||||
pendingSize={pendingSize}
|
||||
/>
|
||||
</Route>
|
||||
<Route path={relativePath('/feed/replies')}>
|
||||
<PostRepliesRoutes
|
||||
baseUrl={relativePath('/feed/replies')}
|
||||
association={association}
|
||||
vip={vip}
|
||||
pendingSize={pendingSize}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
</Col>
|
||||
);
|
||||
|
@ -3,6 +3,7 @@ import { Association, GraphNode, Group, Post } from '@urbit/api';
|
||||
import { BigInteger } from 'big-integer';
|
||||
import { History } from 'history';
|
||||
import React, { Ref } from 'react';
|
||||
import { getPostRoute } from '~/logic/lib/graph';
|
||||
import { isWriter } from '~/logic/lib/group';
|
||||
import { withHovering } from '~/logic/lib/util';
|
||||
import { Mention } from '~/views/components/MentionText';
|
||||
@ -70,21 +71,19 @@ class PostItem extends React.Component<PostItemProps, PostItemState> {
|
||||
}
|
||||
|
||||
navigateToChildren() {
|
||||
const { history, baseUrl, index, isParent, isThread, isHierarchical } = this.props;
|
||||
const {
|
||||
isHierarchical,
|
||||
history,
|
||||
index,
|
||||
isParent,
|
||||
isThread,
|
||||
association
|
||||
} = this.props;
|
||||
if (isParent) {
|
||||
return;
|
||||
}
|
||||
let indexString = '';
|
||||
|
||||
index.forEach((i) => {
|
||||
indexString = indexString + '/' + i.toString();
|
||||
});
|
||||
|
||||
if (!isThread && !isHierarchical) {
|
||||
history.push(`${baseUrl}/feed/thread${indexString}`);
|
||||
} else {
|
||||
history.push(`${baseUrl}/feed/replies${indexString}`);
|
||||
}
|
||||
history.push(getPostRoute(association.resource, index, !isThread && !isHierarchical));
|
||||
}
|
||||
|
||||
submitCallback() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Box, Col, Text } from '@tlon/indigo-react';
|
||||
import { GraphNode } from '@urbit/api';
|
||||
import { Association, PermVariation } from '@urbit/api';
|
||||
import React, { useEffect } from 'react';
|
||||
import { resourceFromPath } from '~/logic/lib/group';
|
||||
import useGraphState, { GraphState, useGraph } from '~/logic/state/graph';
|
||||
@ -7,31 +7,64 @@ import { Loading } from '~/views/components/Loading';
|
||||
import PostFeed from './PostFeed';
|
||||
import PostItem from './PostItem/PostItem';
|
||||
import { stringToArr, arrToString } from '~/views/components/ArrayVirtualScroller';
|
||||
import { useHistory } from 'react-router';
|
||||
|
||||
const graphSel = (s: GraphState) => s.getNode;
|
||||
import { useGroupForAssoc } from '~/logic/state/group';
|
||||
import { Switch, useParams, Route, useHistory } from 'react-router';
|
||||
import bigInt, { BigInteger } from 'big-integer';
|
||||
import { getNodeFromGraph } from '~/logic/lib/graph';
|
||||
|
||||
export default function PostReplies(props) {
|
||||
interface PostRepliesProps {
|
||||
baseUrl: string;
|
||||
association: Association;
|
||||
pendingSize: number;
|
||||
vip: PermVariation;
|
||||
index?: BigInteger[];
|
||||
}
|
||||
|
||||
export function PostRepliesRoutes(props: PostRepliesProps) {
|
||||
const { atom } = useParams<{ atom?: string }>();
|
||||
const index = atom
|
||||
? [...(props.index || []), bigInt(atom)]
|
||||
: (props.index || []);
|
||||
|
||||
const { baseUrl } = props;
|
||||
const makePath = (s: string) => baseUrl + s;
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route path={makePath('/:atom')} render={(routeProps) => {
|
||||
const { url } = routeProps.match;
|
||||
return (
|
||||
<PostRepliesRoutes {...props} baseUrl={url} index={index} />
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route path={baseUrl}>
|
||||
<PostReplies {...props} index={index} />
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
|
||||
export default function PostReplies(props: PostRepliesProps) {
|
||||
const {
|
||||
baseUrl,
|
||||
association,
|
||||
graphPath,
|
||||
group,
|
||||
vip,
|
||||
pendingSize
|
||||
pendingSize,
|
||||
index
|
||||
} = props;
|
||||
const history = useHistory();
|
||||
const getNode = useGraphState(graphSel);
|
||||
const group = useGroupForAssoc(association);
|
||||
const graphPath = association.resource;
|
||||
|
||||
const graphRid = resourceFromPath(graphPath);
|
||||
let graph = useGraph(graphRid.ship, graphRid.name);
|
||||
const graph = useGraph(graphRid.ship, graphRid.name);
|
||||
|
||||
const shouldRenderFeed = Boolean(graph);
|
||||
|
||||
const locationUrl =
|
||||
props.locationUrl.replace(`${baseUrl}/feed/replies`, '');
|
||||
const index = stringToArr(locationUrl);
|
||||
|
||||
useEffect(() => {
|
||||
if (graphRid.ship === '~zod' && graphRid.name === 'null') {
|
||||
return;
|
||||
@ -41,17 +74,8 @@ export default function PostReplies(props) {
|
||||
return;
|
||||
}
|
||||
|
||||
const i = [];
|
||||
for (const k of index) {
|
||||
i.push(k);
|
||||
// TODO: why can't I use await?
|
||||
getNode(
|
||||
graphRid.ship,
|
||||
graphRid.name,
|
||||
arrToString(i)
|
||||
);
|
||||
}
|
||||
}, [graphPath, arrToString(index)]);
|
||||
getNode(graphRid.ship, graphRid.name, `/${index[0]}`);
|
||||
}, [association.resource, index]);
|
||||
|
||||
if (!shouldRenderFeed) {
|
||||
return (
|
||||
@ -61,31 +85,17 @@ export default function PostReplies(props) {
|
||||
);
|
||||
}
|
||||
|
||||
let node: GraphNode;
|
||||
let parentNode;
|
||||
index.forEach((i, idx) => {
|
||||
if (!graph) {
|
||||
return null;
|
||||
}
|
||||
node = graph.get(i);
|
||||
if(idx < index.length - 1) {
|
||||
parentNode = node;
|
||||
}
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
graph = node.children;
|
||||
});
|
||||
const node = getNodeFromGraph(graph, index);
|
||||
const parentNode = index.length > 1 && getNodeFromGraph(graph, index.slice(0, -1));
|
||||
|
||||
if (!node || !graph) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const first = graph.peekLargest()?.[0];
|
||||
const first = node?.children?.peekLargest()?.[0];
|
||||
if (!first) {
|
||||
return (
|
||||
<Col
|
||||
key={`/replies/${locationUrl}`}
|
||||
width="100%"
|
||||
height="100%"
|
||||
alignItems="center" overflowY="scroll"
|
||||
@ -98,10 +108,10 @@ export default function PostReplies(props) {
|
||||
association={association}
|
||||
index={index}
|
||||
baseUrl={baseUrl}
|
||||
history={history}
|
||||
isParent={true}
|
||||
parentPost={parentNode?.post}
|
||||
vip={vip}
|
||||
history={history}
|
||||
group={group}
|
||||
/>
|
||||
</Box>
|
||||
@ -125,9 +135,9 @@ export default function PostReplies(props) {
|
||||
return (
|
||||
<Box height="calc(100% - 48px)" width="100%" alignItems="center" pl={1} pt={3}>
|
||||
<PostFeed
|
||||
key={`/replies/${locationUrl}`}
|
||||
key={location.pathname}
|
||||
graphPath={graphPath}
|
||||
graph={graph}
|
||||
graph={node.children}
|
||||
grandparentNode={parentNode}
|
||||
parentNode={node}
|
||||
pendingSize={pendingSize}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Box, Col, Text } from '@tlon/indigo-react';
|
||||
import bigInt from 'big-integer';
|
||||
import bigInt, { BigInteger } from 'big-integer';
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect
|
||||
} from 'react';
|
||||
import { resourceFromPath } from '~/logic/lib/group';
|
||||
@ -9,46 +10,68 @@ import { arrToString } from '~/views/components/ArrayVirtualScroller';
|
||||
import useGraphState from '~/logic/state/graph';
|
||||
import PostFlatFeed from './PostFlatFeed';
|
||||
import PostInput from './PostInput';
|
||||
import { Association, PermVariation } from '@urbit/api';
|
||||
import { useParams, Switch, Route } from 'react-router';
|
||||
import {useGroupForAssoc} from '~/logic/state/group';
|
||||
|
||||
export default function PostThread(props) {
|
||||
export function PostThreadRoutes(props: PostThreadProps) {
|
||||
const { atom } = useParams<{ atom?: string }>();
|
||||
const index = atom
|
||||
? [...(props.index || []), bigInt(atom)]
|
||||
: (props.index || []);
|
||||
|
||||
const { baseUrl } = props;
|
||||
const makePath = (s: string) => baseUrl + s;
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route path={makePath('/:atom')} render={(routeProps) => {
|
||||
const { url } = routeProps.match;
|
||||
return (
|
||||
<PostThreadRoutes {...props} baseUrl={url} index={index} />
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route path={baseUrl}>
|
||||
<PostThread {...props} index={index} />
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
interface PostThreadProps {
|
||||
baseUrl: string;
|
||||
association: Association;
|
||||
pendingSize: number;
|
||||
vip: PermVariation;
|
||||
index?: BigInteger[];
|
||||
}
|
||||
|
||||
export default function PostThread(props: PostThreadProps) {
|
||||
const {
|
||||
baseUrl,
|
||||
association,
|
||||
graphPath,
|
||||
group,
|
||||
vip,
|
||||
pendingSize
|
||||
pendingSize,
|
||||
index = []
|
||||
} = props;
|
||||
|
||||
const getFirstborn = useGraphState(s => s.getFirstborn);
|
||||
const group = useGroupForAssoc(association);
|
||||
|
||||
const graphResource =
|
||||
graphPath ? resourceFromPath(graphPath) : resourceFromPath('/ship/~zod/null');
|
||||
|
||||
const locationUrl = props.locationUrl.replace(`${baseUrl}/feed/thread`, '');
|
||||
const index = locationUrl.split('/').slice(1).map(ind => bigInt(ind));
|
||||
const { ship, name } = resourceFromPath(association.resource);
|
||||
|
||||
useEffect(() => {
|
||||
if (graphResource.ship === '~zod' && graphResource.name === 'null') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (index.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
getFirstborn(
|
||||
graphResource.ship,
|
||||
graphResource.name,
|
||||
arrToString(index)
|
||||
);
|
||||
}, [graphPath, props.locationUrl]);
|
||||
getFirstborn(ship, name, `/${index.map(i => i.toString()).join('/')}`);
|
||||
}, [association.resource, index]);
|
||||
|
||||
const threadGraphs = useGraphState(state => state.threadGraphs);
|
||||
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
|
||||
const graphId = `${ship.slice(1)}/${name}`;
|
||||
const threadGraph = useGraphState(useCallback(s => s.threadGraphs[graphId] || {}, [graphId]));
|
||||
|
||||
const shouldRenderFeed =
|
||||
graphId in threadGraphs && arrToString(index) in threadGraphs[graphId];
|
||||
const shouldRenderFeed = arrToString(index) in threadGraph;
|
||||
|
||||
if (!shouldRenderFeed) {
|
||||
return (
|
||||
@ -60,9 +83,9 @@ export default function PostThread(props) {
|
||||
|
||||
// TODO: improve performance characteristics of the useGraphState required
|
||||
// to fetch this
|
||||
const threadGraph = threadGraphs[graphId][arrToString(index)];
|
||||
const thread = threadGraph[arrToString(index)];
|
||||
|
||||
const first = threadGraph.peekLargest()?.[0];
|
||||
const first = thread.peekLargest()?.[0];
|
||||
if (!first) {
|
||||
return (
|
||||
<Col
|
||||
@ -81,7 +104,7 @@ export default function PostThread(props) {
|
||||
alignItems="center"
|
||||
>
|
||||
<PostInput
|
||||
graphPath={graphPath}
|
||||
graphPath={association.resource}
|
||||
group={group}
|
||||
association={association}
|
||||
vip={vip}
|
||||
@ -107,9 +130,9 @@ export default function PostThread(props) {
|
||||
return (
|
||||
<Box height="calc(100% - 48px)" width="100%" alignItems="center" pl={1}>
|
||||
<PostFlatFeed
|
||||
key={`/thread/${locationUrl}`}
|
||||
graphPath={graphPath}
|
||||
flatGraph={threadGraph}
|
||||
key={location.pathname}
|
||||
graphPath={association.resource}
|
||||
flatGraph={thread}
|
||||
pendingSize={pendingSize}
|
||||
association={association}
|
||||
group={group}
|
||||
|
Loading…
Reference in New Issue
Block a user