mirror of
https://github.com/ilyakooo0/urbit.git
synced 2025-01-07 07:30:23 +03:00
interface: reworked thread view so that one can navigate to it from any child to see the conversation around that particular child
This commit is contained in:
parent
43a7c12ef7
commit
6b102450a5
@ -361,15 +361,18 @@ export default class GraphApi extends BaseApi<StoreState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFirstborn(ship: string, resource: string, topAncestor: string) {
|
async getFirstborn(ship: string, resource: string, index = '') {
|
||||||
const top = topAncestor ? decToUd(topAncestor) : null;
|
const idx = index.split('/').map(decToUd).join('/');
|
||||||
const data = await this.scry<any>('graph-store',
|
const data = await this.scry<any>('graph-store',
|
||||||
`/firstborn/${ship}/${resource}/${top}`
|
`/firstborn/${ship}/${resource}/${idx}`
|
||||||
);
|
);
|
||||||
const node = data['graph-update'];
|
const node = data['graph-update'];
|
||||||
this.store.handleEvent({
|
this.store.handleEvent({
|
||||||
data: {
|
data: {
|
||||||
'graph-update-thread': node,
|
'graph-update-thread': {
|
||||||
|
index,
|
||||||
|
...node
|
||||||
|
},
|
||||||
'graph-update': node
|
'graph-update': node
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -67,6 +67,7 @@ const addNodesFlat = (json: any, state: GraphState): GraphState => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const indices = Array.from(Object.keys(data.nodes));
|
const indices = Array.from(Object.keys(data.nodes));
|
||||||
|
console.log(indices);
|
||||||
|
|
||||||
indices.forEach((index) => {
|
indices.forEach((index) => {
|
||||||
if (index.split('/').length === 0) { return; }
|
if (index.split('/').length === 0) { return; }
|
||||||
@ -85,7 +86,9 @@ const addNodesFlat = (json: any, state: GraphState): GraphState => {
|
|||||||
|
|
||||||
const addNodesThread = (json: any, state: GraphState): GraphState => {
|
const addNodesThread = (json: any, state: GraphState): GraphState => {
|
||||||
const data = _.get(json, 'add-nodes', false);
|
const data = _.get(json, 'add-nodes', false);
|
||||||
if (data) {
|
const parentIndex = _.get(json, 'index', false);
|
||||||
|
console.log(json);
|
||||||
|
if (data && parentIndex) {
|
||||||
if (!('threadGraphs' in state)) {
|
if (!('threadGraphs' in state)) {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@ -96,21 +99,25 @@ const addNodesThread = (json: any, state: GraphState): GraphState => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const indices = Array.from(Object.keys(data.nodes));
|
const indices = Array.from(Object.keys(data.nodes));
|
||||||
|
if (!(parentIndex in state.threadGraphs[resource])) {
|
||||||
|
state.threadGraphs[resource][parentIndex] = new BigIntArrayOrderedMap([], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(state.threadGraphs);
|
||||||
|
|
||||||
indices.forEach((index) => {
|
indices.forEach((index) => {
|
||||||
if (index.split('/').length === 0) { return; }
|
if (index.split('/').length === 0) { return; }
|
||||||
const indexArr = index.split('/').slice(1).map((ind) => bigInt(ind));
|
const indexArr = index.split('/').slice(1).map((ind) => bigInt(ind));
|
||||||
|
|
||||||
if (indexArr.length === 0) { return state; }
|
if (indexArr.length === 0) { return state; }
|
||||||
|
|
||||||
let parentKey = indexArr[0].toString();
|
|
||||||
if (!(parentKey in state.threadGraphs[resource])) {
|
|
||||||
state.threadGraphs[resource][parentKey] = new BigIntArrayOrderedMap([], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let node = data.nodes[index];
|
let node = data.nodes[index];
|
||||||
node.children = mapifyChildren({});
|
state.threadGraphs[resource][parentIndex] =
|
||||||
state.threadGraphs[resource][parentKey] =
|
state.threadGraphs[resource][parentIndex].set(indexArr,
|
||||||
state.threadGraphs[resource][parentKey].set(indexArr, node);
|
produce(node, (draft) => {
|
||||||
|
draft.children = mapifyChildren({});
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -148,6 +148,28 @@ export function useGraph(ship: string, name: string) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useFlatGraph(ship: string, name: string) {
|
||||||
|
return useGraphState(
|
||||||
|
useCallback(s => s.flatGraphs[`${deSig(ship)}/${name}`], [ship, name])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useThreadGraph(ship: string, name: string, index: string) {
|
||||||
|
return useGraphState(
|
||||||
|
useCallback(s => s.threadGraphs[`${deSig(ship)}/${name}/${index}`], [
|
||||||
|
ship,
|
||||||
|
name,
|
||||||
|
index
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGraphTimesentMap(ship: string, name: string) {
|
||||||
|
return useGraphState(
|
||||||
|
useCallback(s => s.graphTimesentMap[`${deSig(ship)}/${name}`], [ship, name])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function useGraphForAssoc(association: Association) {
|
export function useGraphForAssoc(association: Association) {
|
||||||
const { resource } = association;
|
const { resource } = association;
|
||||||
const { ship, name } = resourceFromPath(resource);
|
const { ship, name } = resourceFromPath(resource);
|
||||||
|
@ -4,6 +4,7 @@ import React from 'react';
|
|||||||
|
|
||||||
export function GroupFeedHeader(props) {
|
export function GroupFeedHeader(props) {
|
||||||
const { baseUrl, history, graphResource, vip } = props;
|
const { baseUrl, history, graphResource, vip } = props;
|
||||||
|
|
||||||
let graph = props.graph;
|
let graph = props.graph;
|
||||||
const historyLocation = history.location.pathname;
|
const historyLocation = history.location.pathname;
|
||||||
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
|
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
|
||||||
|
@ -4,9 +4,9 @@ import React, {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { Route, Switch, useHistory } from 'react-router-dom';
|
import { Route, Switch, useHistory } from 'react-router-dom';
|
||||||
import { resourceFromPath } from '~/logic/lib/group';
|
import { resourceFromPath } from '~/logic/lib/group';
|
||||||
import useGraphState from '~/logic/state/graph';
|
import { useFlatGraph, useGraphTimesentMap } from '~/logic/state/graph';
|
||||||
import useGroupState from '~/logic/state/group';
|
import { useGroup } from '~/logic/state/group';
|
||||||
import useMetadataState from '~/logic/state/metadata';
|
import { useAssocForGraph } from '~/logic/state/metadata';
|
||||||
import { Loading } from '~/views/components/Loading';
|
import { Loading } from '~/views/components/Loading';
|
||||||
import { GroupFeedHeader } from './GroupFeedHeader';
|
import { GroupFeedHeader } from './GroupFeedHeader';
|
||||||
import PostThread from './Post/PostThread';
|
import PostThread from './Post/PostThread';
|
||||||
@ -23,36 +23,27 @@ function GroupFlatFeed(props) {
|
|||||||
vip
|
vip
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const groups = useGroupState(state => state.groups);
|
const group = useGroup(groupPath);
|
||||||
const group = groups[groupPath];
|
|
||||||
|
|
||||||
const associations = useMetadataState(state => state.associations);
|
const graphRid =
|
||||||
const flatGraphs = useGraphState(state => state.flatGraphs);
|
|
||||||
|
|
||||||
const graphResource =
|
|
||||||
graphPath ? resourceFromPath(graphPath) : resourceFromPath('/ship/~zod/null');
|
graphPath ? resourceFromPath(graphPath) : resourceFromPath('/ship/~zod/null');
|
||||||
const graphTimesentMap = useGraphState(state => state.graphTimesentMap);
|
|
||||||
|
|
||||||
const pendingSize = Object.keys(
|
const flatGraph = useFlatGraph(graphRid.ship, graphRid.name);
|
||||||
graphTimesentMap[`${graphResource.ship.slice(1)}/${graphResource.name}`] ||
|
const association = useAssocForGraph(graphPath);
|
||||||
{}
|
|
||||||
).length;
|
const graphTimesentMap = useGraphTimesentMap(graphRid.ship, graphRid.name);
|
||||||
|
const pendingSize = Object.keys(graphTimesentMap || {}).length;
|
||||||
|
|
||||||
const relativePath = path => baseUrl + path;
|
const relativePath = path => baseUrl + path;
|
||||||
const association = associations.graph[graphPath];
|
|
||||||
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const locationUrl = history.location.pathname;
|
const locationUrl = history.location.pathname;
|
||||||
|
|
||||||
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
|
|
||||||
const flatGraph = flatGraphs[graphId];
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// TODO: VirtualScroller should support lower starting values than 100
|
// TODO: VirtualScroller should support lower starting values than 100
|
||||||
if (graphResource.ship === '~zod' && graphResource.name === 'null') {
|
if (graphRid.ship === '~zod' && graphRid.name === 'null') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
api.graph.getDeepOlderThan(graphResource.ship, graphResource.name, null, 100);
|
api.graph.getDeepOlderThan(graphRid.ship, graphRid.name, null, 100);
|
||||||
api.hark.markCountAsRead(association, '/', 'post');
|
api.hark.markCountAsRead(association, '/', 'post');
|
||||||
}, [graphPath]);
|
}, [graphPath]);
|
||||||
|
|
||||||
@ -72,9 +63,8 @@ function GroupFlatFeed(props) {
|
|||||||
<GroupFeedHeader
|
<GroupFeedHeader
|
||||||
baseUrl={baseUrl}
|
baseUrl={baseUrl}
|
||||||
history={history}
|
history={history}
|
||||||
graphs={flatGraphs}
|
|
||||||
vip={vip}
|
vip={vip}
|
||||||
graphResource={graphResource}
|
graphResource={graphRid}
|
||||||
/>
|
/>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
|
@ -55,7 +55,6 @@ class PostFlatFeed extends React.Component<PostFeedProps, PostFeedState> {
|
|||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const node = flatGraph.get(index);
|
const node = flatGraph.get(index);
|
||||||
console.log(arrToString(index))
|
|
||||||
const parentNode = index.length > 1 ?
|
const parentNode = index.length > 1 ?
|
||||||
flatGraph.get(index.slice(0, index.length - 1)) : null;
|
flatGraph.get(index.slice(0, index.length - 1)) : null;
|
||||||
|
|
||||||
@ -63,6 +62,10 @@ class PostFlatFeed extends React.Component<PostFeedProps, PostFeedState> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arrToString(index) !== node.post.index) {
|
||||||
|
console.log(node.post.index, arrToString(index), node);
|
||||||
|
}
|
||||||
|
|
||||||
const first = flatGraph.peekLargest()?.[0];
|
const first = flatGraph.peekLargest()?.[0];
|
||||||
const last = flatGraph.peekSmallest()?.[0];
|
const last = flatGraph.peekSmallest()?.[0];
|
||||||
const post = node?.post;
|
const post = node?.post;
|
||||||
|
@ -47,6 +47,7 @@ const PostInput = (props: PostInputProps): ReactElement | null => {
|
|||||||
const [code, toggleCode] = useToggleState(false);
|
const [code, toggleCode] = useToggleState(false);
|
||||||
const { canUpload, promptUpload, uploading } = useStorage();
|
const { canUpload, promptUpload, uploading } = useStorage();
|
||||||
const [postContent, setPostContent] = useState('');
|
const [postContent, setPostContent] = useState('');
|
||||||
|
|
||||||
const uploadImage = useCallback(async () => {
|
const uploadImage = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
setDisabled(true);
|
setDisabled(true);
|
||||||
|
@ -41,8 +41,7 @@ class PostItem extends React.Component<PostItemProps, PostItemState> {
|
|||||||
|
|
||||||
this.state = { inReplyMode: false };
|
this.state = { inReplyMode: false };
|
||||||
this.toggleReplyMode = this.toggleReplyMode.bind(this);
|
this.toggleReplyMode = this.toggleReplyMode.bind(this);
|
||||||
this.navigateToReplies = this.navigateToReplies.bind(this);
|
this.navigateToChildren = this.navigateToChildren.bind(this);
|
||||||
this.navigateToThread = this.navigateToThread.bind(this);
|
|
||||||
this.submitCallback = this.submitCallback.bind(this);
|
this.submitCallback = this.submitCallback.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,22 +68,8 @@ class PostItem extends React.Component<PostItemProps, PostItemState> {
|
|||||||
this.setState({ inReplyMode: !this.state.inReplyMode });
|
this.setState({ inReplyMode: !this.state.inReplyMode });
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToReplies() {
|
navigateToChildren() {
|
||||||
const { history, baseUrl, index, isParent } = this.props;
|
const { history, baseUrl, index, isParent, isThread } = this.props;
|
||||||
if (isParent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let indexString = '';
|
|
||||||
|
|
||||||
index.forEach((i) => {
|
|
||||||
indexString = indexString + '/' + i.toString();
|
|
||||||
});
|
|
||||||
|
|
||||||
history.push(`${baseUrl}/feed/replies${indexString}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
navigateToThread() {
|
|
||||||
const { history, baseUrl, index, isParent } = this.props;
|
|
||||||
if (isParent) {
|
if (isParent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -94,7 +79,10 @@ class PostItem extends React.Component<PostItemProps, PostItemState> {
|
|||||||
indexString = indexString + '/' + i.toString();
|
indexString = indexString + '/' + i.toString();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: ensure that the logic here works properly
|
||||||
history.push(`${baseUrl}/feed/thread${indexString}`);
|
history.push(`${baseUrl}/feed/thread${indexString}`);
|
||||||
|
|
||||||
|
//history.push(`${baseUrl}/feed/replies${indexString}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
submitCallback() {
|
submitCallback() {
|
||||||
@ -148,7 +136,7 @@ class PostItem extends React.Component<PostItemProps, PostItemState> {
|
|||||||
width="100%"
|
width="100%"
|
||||||
maxWidth="600px"
|
maxWidth="600px"
|
||||||
backgroundColor={ hovering ? 'washedGray' : 'transparent' }
|
backgroundColor={ hovering ? 'washedGray' : 'transparent' }
|
||||||
onClick={isThread ? this.navigateToReplies : this.navigateToThread}
|
onClick={this.navigateToChildren}
|
||||||
cursor={isParent ? "default": "pointer"}
|
cursor={isParent ? "default": "pointer"}
|
||||||
{...bind}>
|
{...bind}>
|
||||||
{ (postExists) ? (
|
{ (postExists) ? (
|
||||||
|
@ -5,6 +5,7 @@ import React, {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { resourceFromPath } from '~/logic/lib/group';
|
import { resourceFromPath } from '~/logic/lib/group';
|
||||||
import { Loading } from '~/views/components/Loading';
|
import { Loading } from '~/views/components/Loading';
|
||||||
|
import { arrToString } from '~/views/components/ArrayVirtualScroller';
|
||||||
import useGraphState from '~/logic/state/graph';
|
import useGraphState from '~/logic/state/graph';
|
||||||
import PostFlatFeed from './PostFlatFeed';
|
import PostFlatFeed from './PostFlatFeed';
|
||||||
import PostItem from './PostItem/PostItem';
|
import PostItem from './PostItem/PostItem';
|
||||||
@ -36,12 +37,11 @@ export default function PostThread(props) {
|
|||||||
if (index.length < 1) {
|
if (index.length < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(index[0].toString());
|
|
||||||
|
|
||||||
api.graph.getFirstborn(
|
api.graph.getFirstborn(
|
||||||
graphResource.ship,
|
graphResource.ship,
|
||||||
graphResource.name,
|
graphResource.name,
|
||||||
index[0].toString()
|
arrToString(index)
|
||||||
);
|
);
|
||||||
}, [graphPath, props.locationUrl]);
|
}, [graphPath, props.locationUrl]);
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ export default function PostThread(props) {
|
|||||||
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
|
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
|
||||||
|
|
||||||
const shouldRenderFeed =
|
const shouldRenderFeed =
|
||||||
graphId in threadGraphs && index[0].toString() in threadGraphs[graphId];
|
graphId in threadGraphs && arrToString(index) in threadGraphs[graphId];
|
||||||
|
|
||||||
if (!shouldRenderFeed) {
|
if (!shouldRenderFeed) {
|
||||||
return (
|
return (
|
||||||
@ -59,7 +59,9 @@ export default function PostThread(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const threadGraph = threadGraphs[graphId][index[0].toString()];
|
// TODO: improve performance characteristics of the useGraphState required
|
||||||
|
// to fetch this
|
||||||
|
const threadGraph = threadGraphs[graphId][arrToString(index)];
|
||||||
|
|
||||||
const first = threadGraph.peekLargest()?.[0];
|
const first = threadGraph.peekLargest()?.[0];
|
||||||
if (!first) {
|
if (!first) {
|
||||||
|
Loading…
Reference in New Issue
Block a user