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:
Logan Allen 2021-05-18 16:55:43 -05:00
parent 43a7c12ef7
commit 6b102450a5
9 changed files with 77 additions and 60 deletions

View File

@ -361,15 +361,18 @@ export default class GraphApi extends BaseApi<StoreState> {
});
}
async getFirstborn(ship: string, resource: string, topAncestor: string) {
const top = topAncestor ? decToUd(topAncestor) : null;
async getFirstborn(ship: string, resource: string, index = '') {
const idx = index.split('/').map(decToUd).join('/');
const data = await this.scry<any>('graph-store',
`/firstborn/${ship}/${resource}/${top}`
`/firstborn/${ship}/${resource}/${idx}`
);
const node = data['graph-update'];
this.store.handleEvent({
data: {
'graph-update-thread': node,
'graph-update-thread': {
index,
...node
},
'graph-update': node
},
});

View File

@ -67,6 +67,7 @@ const addNodesFlat = (json: any, state: GraphState): GraphState => {
}
const indices = Array.from(Object.keys(data.nodes));
console.log(indices);
indices.forEach((index) => {
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 data = _.get(json, 'add-nodes', false);
if (data) {
const parentIndex = _.get(json, 'index', false);
console.log(json);
if (data && parentIndex) {
if (!('threadGraphs' in state)) {
return state;
}
@ -96,21 +99,25 @@ const addNodesThread = (json: any, state: GraphState): GraphState => {
}
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) => {
if (index.split('/').length === 0) { return; }
const indexArr = index.split('/').slice(1).map((ind) => bigInt(ind));
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];
node.children = mapifyChildren({});
state.threadGraphs[resource][parentKey] =
state.threadGraphs[resource][parentKey].set(indexArr, node);
state.threadGraphs[resource][parentIndex] =
state.threadGraphs[resource][parentIndex].set(indexArr,
produce(node, (draft) => {
draft.children = mapifyChildren({});
})
);
});
}

View File

@ -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) {
const { resource } = association;
const { ship, name } = resourceFromPath(resource);

View File

@ -4,6 +4,7 @@ import React from 'react';
export function GroupFeedHeader(props) {
const { baseUrl, history, graphResource, vip } = props;
let graph = props.graph;
const historyLocation = history.location.pathname;
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;

View File

@ -4,9 +4,9 @@ import React, {
} from 'react';
import { Route, Switch, useHistory } from 'react-router-dom';
import { resourceFromPath } from '~/logic/lib/group';
import useGraphState from '~/logic/state/graph';
import useGroupState from '~/logic/state/group';
import useMetadataState from '~/logic/state/metadata';
import { useFlatGraph, useGraphTimesentMap } from '~/logic/state/graph';
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';
@ -23,36 +23,27 @@ function GroupFlatFeed(props) {
vip
} = props;
const groups = useGroupState(state => state.groups);
const group = groups[groupPath];
const group = useGroup(groupPath);
const associations = useMetadataState(state => state.associations);
const flatGraphs = useGraphState(state => state.flatGraphs);
const graphResource =
const graphRid =
graphPath ? resourceFromPath(graphPath) : resourceFromPath('/ship/~zod/null');
const graphTimesentMap = useGraphState(state => state.graphTimesentMap);
const pendingSize = Object.keys(
graphTimesentMap[`${graphResource.ship.slice(1)}/${graphResource.name}`] ||
{}
).length;
const flatGraph = useFlatGraph(graphRid.ship, graphRid.name);
const association = useAssocForGraph(graphPath);
const graphTimesentMap = useGraphTimesentMap(graphRid.ship, graphRid.name);
const pendingSize = Object.keys(graphTimesentMap || {}).length;
const relativePath = path => baseUrl + path;
const association = associations.graph[graphPath];
const history = useHistory();
const locationUrl = history.location.pathname;
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
const flatGraph = flatGraphs[graphId];
useEffect(() => {
// TODO: VirtualScroller should support lower starting values than 100
if (graphResource.ship === '~zod' && graphResource.name === 'null') {
if (graphRid.ship === '~zod' && graphRid.name === 'null') {
return;
}
api.graph.getDeepOlderThan(graphResource.ship, graphResource.name, null, 100);
api.graph.getDeepOlderThan(graphRid.ship, graphRid.name, null, 100);
api.hark.markCountAsRead(association, '/', 'post');
}, [graphPath]);
@ -72,9 +63,8 @@ function GroupFlatFeed(props) {
<GroupFeedHeader
baseUrl={baseUrl}
history={history}
graphs={flatGraphs}
vip={vip}
graphResource={graphResource}
graphResource={graphRid}
/>
<Switch>
<Route

View File

@ -55,7 +55,6 @@ class PostFlatFeed extends React.Component<PostFeedProps, PostFeedState> {
} = this.props;
const node = flatGraph.get(index);
console.log(arrToString(index))
const parentNode = index.length > 1 ?
flatGraph.get(index.slice(0, index.length - 1)) : null;
@ -63,6 +62,10 @@ class PostFlatFeed extends React.Component<PostFeedProps, PostFeedState> {
return null;
}
if (arrToString(index) !== node.post.index) {
console.log(node.post.index, arrToString(index), node);
}
const first = flatGraph.peekLargest()?.[0];
const last = flatGraph.peekSmallest()?.[0];
const post = node?.post;

View File

@ -47,6 +47,7 @@ const PostInput = (props: PostInputProps): ReactElement | null => {
const [code, toggleCode] = useToggleState(false);
const { canUpload, promptUpload, uploading } = useStorage();
const [postContent, setPostContent] = useState('');
const uploadImage = useCallback(async () => {
try {
setDisabled(true);

View File

@ -41,8 +41,7 @@ class PostItem extends React.Component<PostItemProps, PostItemState> {
this.state = { inReplyMode: false };
this.toggleReplyMode = this.toggleReplyMode.bind(this);
this.navigateToReplies = this.navigateToReplies.bind(this);
this.navigateToThread = this.navigateToThread.bind(this);
this.navigateToChildren = this.navigateToChildren.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 });
}
navigateToReplies() {
const { history, baseUrl, index, isParent } = 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;
navigateToChildren() {
const { history, baseUrl, index, isParent, isThread } = this.props;
if (isParent) {
return;
}
@ -94,7 +79,10 @@ class PostItem extends React.Component<PostItemProps, PostItemState> {
indexString = indexString + '/' + i.toString();
});
// TODO: ensure that the logic here works properly
history.push(`${baseUrl}/feed/thread${indexString}`);
//history.push(`${baseUrl}/feed/replies${indexString}`);
}
submitCallback() {
@ -148,7 +136,7 @@ class PostItem extends React.Component<PostItemProps, PostItemState> {
width="100%"
maxWidth="600px"
backgroundColor={ hovering ? 'washedGray' : 'transparent' }
onClick={isThread ? this.navigateToReplies : this.navigateToThread}
onClick={this.navigateToChildren}
cursor={isParent ? "default": "pointer"}
{...bind}>
{ (postExists) ? (

View File

@ -5,6 +5,7 @@ import React, {
} from 'react';
import { resourceFromPath } from '~/logic/lib/group';
import { Loading } from '~/views/components/Loading';
import { arrToString } from '~/views/components/ArrayVirtualScroller';
import useGraphState from '~/logic/state/graph';
import PostFlatFeed from './PostFlatFeed';
import PostItem from './PostItem/PostItem';
@ -36,12 +37,11 @@ export default function PostThread(props) {
if (index.length < 1) {
return;
}
console.log(index[0].toString());
api.graph.getFirstborn(
graphResource.ship,
graphResource.name,
index[0].toString()
arrToString(index)
);
}, [graphPath, props.locationUrl]);
@ -49,7 +49,7 @@ export default function PostThread(props) {
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
const shouldRenderFeed =
graphId in threadGraphs && index[0].toString() in threadGraphs[graphId];
graphId in threadGraphs && arrToString(index) in threadGraphs[graphId];
if (!shouldRenderFeed) {
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];
if (!first) {