mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-12 15:01:38 +03:00
Merge pull request #4673 from urbit/la/feed-perf
group-feed: improve performance and make mobile load
This commit is contained in:
commit
dd563ac26a
@ -3,29 +3,9 @@ import { StoreState } from '../store/type';
|
||||
import { Path } from '@urbit/api';
|
||||
import _ from 'lodash';
|
||||
|
||||
/**
|
||||
* Path to subscribe on and app to subscribe to
|
||||
*/
|
||||
type AppSubscription = [Path, string];
|
||||
|
||||
const groupSubscriptions: AppSubscription[] = [
|
||||
];
|
||||
|
||||
const graphSubscriptions: AppSubscription[] = [
|
||||
['/updates', 'graph-store']
|
||||
];
|
||||
|
||||
type AppName = 'groups' | 'graph';
|
||||
const appSubscriptions: Record<AppName, AppSubscription[]> = {
|
||||
groups: groupSubscriptions,
|
||||
graph: graphSubscriptions
|
||||
};
|
||||
|
||||
export default class GlobalSubscription extends BaseSubscription<StoreState> {
|
||||
openSubscriptions: Record<AppName, number[]> = {
|
||||
groups: [],
|
||||
graph: []
|
||||
};
|
||||
openSubscriptions: any = {};
|
||||
|
||||
start() {
|
||||
this.subscribe('/all', 'metadata-store');
|
||||
@ -35,7 +15,6 @@ export default class GlobalSubscription extends BaseSubscription<StoreState> {
|
||||
this.subscribe('/groups', 'group-store');
|
||||
this.clearQueue();
|
||||
|
||||
// TODO: update to get /updates
|
||||
this.subscribe('/all', 'contact-store');
|
||||
this.subscribe('/all', 's3-store');
|
||||
this.subscribe('/keys', 'graph-store');
|
||||
@ -45,29 +24,37 @@ export default class GlobalSubscription extends BaseSubscription<StoreState> {
|
||||
this.subscribe('/all', 'settings-store');
|
||||
this.subscribe('/all', 'group-view');
|
||||
this.subscribe('/nacks', 'contact-pull-hook');
|
||||
this.clearQueue();
|
||||
|
||||
this.subscribe('/updates', 'graph-store');
|
||||
}
|
||||
|
||||
subscribe(path: Path, app: string) {
|
||||
if (`${app}${path}` in this.openSubscriptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = super.subscribe(path, app);
|
||||
this.openSubscriptions[`${app}${path}`] = { app, path, id };
|
||||
}
|
||||
|
||||
unsubscribe(id) {
|
||||
for (let key in Object.keys(this.openSubscriptions)) {
|
||||
let val = this.openSubscriptions[key];
|
||||
if (id === val.id) {
|
||||
delete this.openSubscriptions[`${val.app}${val.path}`];
|
||||
super.unsubscribe(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
restart() {
|
||||
super.restart();
|
||||
_.mapValues(this.openSubscriptions, (subs, app: AppName) => {
|
||||
if(subs.length > 0) {
|
||||
this.stopApp(app);
|
||||
this.startApp(app);
|
||||
}
|
||||
});
|
||||
}
|
||||
for (let key in Object.keys(this.openSubscriptions)) {
|
||||
let val = this.openSubscriptions[key];
|
||||
|
||||
startApp(app: AppName) {
|
||||
if(this.openSubscriptions[app].length > 0) {
|
||||
console.log(`${app} already started`);
|
||||
return;
|
||||
unsubscribe(val.id);
|
||||
}
|
||||
this.openSubscriptions[app] =
|
||||
appSubscriptions[app].map(([path, agent]) => this.subscribe(path, agent));
|
||||
}
|
||||
|
||||
stopApp(app: AppName) {
|
||||
this.openSubscriptions[app].map(id => this.unsubscribe(id));
|
||||
this.openSubscriptions[app] = [];
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ registerRoute(
|
||||
// Check to see if the request's destination is style for stylesheets, script for JavaScript, or worker for web worker
|
||||
({ request }) =>
|
||||
request.destination === 'style' ||
|
||||
request.destination === 'script' ||
|
||||
// request.destination === 'script' ||
|
||||
request.destination === 'worker',
|
||||
// Use a Stale While Revalidate caching strategy
|
||||
new StaleWhileRevalidate({
|
||||
|
@ -196,7 +196,10 @@ export function GroupsPane(props: GroupsPaneProps) {
|
||||
return (
|
||||
<>
|
||||
<Helmet defer={false}>
|
||||
<title>{notificationsCount ? `(${String(notificationsCount)}) ` : ''}{ title }</title>
|
||||
<title>
|
||||
{notificationsCount ? `(${String(notificationsCount)}) ` : ''}
|
||||
{ title }
|
||||
</title>
|
||||
</Helmet>
|
||||
<Skeleton
|
||||
mobileHide={shouldHideSidebar}
|
||||
@ -204,14 +207,9 @@ export function GroupsPane(props: GroupsPaneProps) {
|
||||
baseUrl={baseUrl}
|
||||
{...props}>
|
||||
<GroupHome
|
||||
{...routeProps}
|
||||
api={api}
|
||||
baseUrl={baseUrl}
|
||||
associations={associations}
|
||||
groups={groups}
|
||||
groupPath={groupPath}
|
||||
contacts={contacts}
|
||||
workspace={workspace}
|
||||
/>
|
||||
{popovers(routeProps, baseUrl)}
|
||||
</Skeleton>
|
||||
|
@ -10,6 +10,8 @@ import { AsyncButton } from "~/views/components/AsyncButton";
|
||||
import GlobalApi from "~/logic/api/global";
|
||||
import { resourceFromPath, Tag, resourceAsPath } from "@urbit/api";
|
||||
import useGroupState, { useGroup } from "~/logic/state/group";
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
|
||||
interface FormSchema {
|
||||
permissions: GroupFeedPermissions;
|
||||
@ -20,7 +22,13 @@ export function EnableGroupFeed(props: {
|
||||
dismiss: () => void;
|
||||
api: GlobalApi;
|
||||
}) {
|
||||
const { api, groupPath, dismiss } = props;
|
||||
const { api, groupPath, baseUrl } = props;
|
||||
|
||||
const history = useHistory();
|
||||
const dismiss = () => {
|
||||
history.push(baseUrl);
|
||||
};
|
||||
|
||||
const initialValues: FormSchema = {
|
||||
permissions: "everyone",
|
||||
};
|
||||
@ -44,7 +52,7 @@ export function EnableGroupFeed(props: {
|
||||
actions.setStatus({ success: null });
|
||||
dismiss();
|
||||
},
|
||||
[groupPath, dismiss]
|
||||
[groupPath, baseUrl]
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -6,21 +6,26 @@ import { Col } from '@tlon/indigo-react'
|
||||
import { resourceFromPath } from '~/logic/lib/group';
|
||||
import useGraphState from '~/logic/state/graph';
|
||||
import { GroupFeedHeader } from './GroupFeedHeader';
|
||||
import { PostTimeline } from './Post/PostTimeline';
|
||||
import { PostReplies } from './Post/PostReplies';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import PostTimeline from './Post/PostTimeline';
|
||||
import PostReplies from './Post/PostReplies';
|
||||
|
||||
import useMetadataState from '~/logic/state/metadata';
|
||||
|
||||
|
||||
export function GroupFeed(props) {
|
||||
function GroupFeed(props) {
|
||||
const {
|
||||
baseUrl,
|
||||
api,
|
||||
history,
|
||||
associations,
|
||||
graphPath
|
||||
} = props;
|
||||
|
||||
const associations = useMetadataState(state => state.associations);
|
||||
const graphs = useGraphState(state => state.graphs);
|
||||
const graphResource = resourceFromPath(graphPath);
|
||||
const graphTimesentMap = useGraphState(state => state.graphTimesentMap);
|
||||
|
||||
const pendingSize = Object.keys(
|
||||
graphTimesentMap[`${graphResource.ship.slice(1)}/${graphResource.name}`] ||
|
||||
{}
|
||||
@ -29,6 +34,12 @@ export function GroupFeed(props) {
|
||||
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 graph = graphs[graphId];
|
||||
|
||||
useEffect(() => {
|
||||
// TODO: VirtualScroller should support lower starting values than 100
|
||||
api.graph.getNewest(graphResource.ship, graphResource.name, 100);
|
||||
@ -53,11 +64,13 @@ export function GroupFeed(props) {
|
||||
render={(routeProps) => {
|
||||
return (
|
||||
<PostTimeline
|
||||
{...props}
|
||||
baseUrl={baseUrl}
|
||||
api={api}
|
||||
history={history}
|
||||
graphPath={graphPath}
|
||||
association={association}
|
||||
graphs={graphs}
|
||||
pendingSize={pendingSize}
|
||||
graphResource={graphResource} />
|
||||
graph={graph}
|
||||
pendingSize={pendingSize} />
|
||||
);
|
||||
}} />
|
||||
<Route
|
||||
@ -65,11 +78,14 @@ export function GroupFeed(props) {
|
||||
render={(routeProps) => {
|
||||
return (
|
||||
<PostReplies
|
||||
{...props}
|
||||
locationUrl={locationUrl}
|
||||
baseUrl={baseUrl}
|
||||
api={api}
|
||||
history={history}
|
||||
graphPath={graphPath}
|
||||
association={association}
|
||||
graphs={graphs}
|
||||
pendingSize={pendingSize}
|
||||
graphResource={graphResource} />
|
||||
graph={graph}
|
||||
pendingSize={pendingSize} />
|
||||
);
|
||||
}} />
|
||||
</Switch>
|
||||
@ -77,3 +93,6 @@ export function GroupFeed(props) {
|
||||
);
|
||||
}
|
||||
|
||||
GroupFeed.whyDidYouRender = true;
|
||||
|
||||
export { GroupFeed };
|
||||
|
@ -5,20 +5,22 @@ import { EnableGroupFeed } from './EnableGroupFeed';
|
||||
import { EmptyGroupHome } from './EmptyGroupHome';
|
||||
import { GroupFeed } from './GroupFeed';
|
||||
import { AddFeedBanner } from './AddFeedBanner';
|
||||
import {Route, useHistory} from 'react-router-dom';
|
||||
import { Route } from 'react-router-dom';
|
||||
|
||||
import useGroupState from '~/logic/state/group';
|
||||
import useMetadataState from '~/logic/state/metadata';
|
||||
|
||||
|
||||
export function GroupHome(props) {
|
||||
function GroupHome(props) {
|
||||
const {
|
||||
associations,
|
||||
api,
|
||||
groupPath,
|
||||
groups,
|
||||
graphs,
|
||||
baseUrl,
|
||||
contacts,
|
||||
baseUrl
|
||||
} = props;
|
||||
|
||||
const associations = useMetadataState(state => state.associations);
|
||||
const groups = useGroupState(state => state.groups);
|
||||
|
||||
const metadata = associations?.groups[groupPath]?.metadata;
|
||||
const askFeedBanner =
|
||||
metadata &&
|
||||
@ -33,7 +35,6 @@ export function GroupHome(props) {
|
||||
'resource' in metadata.config.group;
|
||||
|
||||
const graphPath = metadata?.config?.group?.resource;
|
||||
const history = useHistory();
|
||||
|
||||
return (
|
||||
<Box width="100%" height="100%" overflow="hidden">
|
||||
@ -42,7 +43,7 @@ export function GroupHome(props) {
|
||||
return (
|
||||
<EnableGroupFeed
|
||||
groupPath={groupPath}
|
||||
dismiss={() => history.push(baseUrl)}
|
||||
baseUrl={baseUrl}
|
||||
api={api}
|
||||
/>
|
||||
);
|
||||
@ -57,13 +58,8 @@ export function GroupHome(props) {
|
||||
) : null }
|
||||
{ isFeedEnabled ? (
|
||||
<GroupFeed
|
||||
associations={associations}
|
||||
groups={groups}
|
||||
contacts={contacts}
|
||||
graphPath={graphPath}
|
||||
graphs={graphs}
|
||||
api={api}
|
||||
history={history}
|
||||
baseUrl={baseUrl} />
|
||||
) : (
|
||||
<EmptyGroupHome {...props} />
|
||||
@ -71,3 +67,5 @@ export function GroupHome(props) {
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export { GroupHome };
|
||||
|
@ -1,15 +1,15 @@
|
||||
import React from 'react';
|
||||
import bigInt from 'big-integer';
|
||||
import VirtualScroller from "~/views/components/VirtualScroller";
|
||||
import PostItem from './PostItem';
|
||||
import PostItem from './PostItem/PostItem';
|
||||
import { Col } from '@tlon/indigo-react';
|
||||
import { resourceFromPath } from '~/logic/lib/group';
|
||||
|
||||
|
||||
const virtualScrollerStyle = {
|
||||
height: "100%"
|
||||
};
|
||||
|
||||
|
||||
export class PostFeed extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -18,14 +18,14 @@ export class PostFeed extends React.Component {
|
||||
this.renderItem = React.forwardRef(({ index, scrollWindow }, ref) => {
|
||||
const {
|
||||
graph,
|
||||
graphResource,
|
||||
contacts,
|
||||
graphPath,
|
||||
api,
|
||||
history,
|
||||
baseUrl,
|
||||
parentNode,
|
||||
association
|
||||
} = this.props;
|
||||
const graphResource = resourceFromPath(graphPath);
|
||||
const node = graph.get(index);
|
||||
if (!node) { return null; }
|
||||
|
||||
@ -39,7 +39,6 @@ export class PostFeed extends React.Component {
|
||||
}) : [];
|
||||
|
||||
if (parentNode && index.eq(first ?? bigInt.zero)) {
|
||||
|
||||
return (
|
||||
<React.Fragment key={index.toString()}>
|
||||
<Col
|
||||
@ -52,8 +51,7 @@ export class PostFeed extends React.Component {
|
||||
key={parentNode.post.index}
|
||||
ref={ref}
|
||||
node={parentNode}
|
||||
contacts={contacts}
|
||||
graphResource={graphResource}
|
||||
graphPath={graphPath}
|
||||
association={association}
|
||||
api={api}
|
||||
index={nodeIndex}
|
||||
@ -65,8 +63,7 @@ export class PostFeed extends React.Component {
|
||||
<PostItem
|
||||
ref={ref}
|
||||
node={node}
|
||||
contacts={contacts}
|
||||
graphResource={graphResource}
|
||||
graphPath={graphPath}
|
||||
association={association}
|
||||
api={api}
|
||||
index={[...nodeIndex, index]}
|
||||
@ -84,8 +81,7 @@ export class PostFeed extends React.Component {
|
||||
key={index.toString()}
|
||||
ref={ref}
|
||||
node={node}
|
||||
contacts={contacts}
|
||||
graphResource={graphResource}
|
||||
graphPath={graphPath}
|
||||
association={association}
|
||||
api={api}
|
||||
index={[...nodeIndex, index]}
|
||||
@ -102,7 +98,8 @@ export class PostFeed extends React.Component {
|
||||
}
|
||||
|
||||
async fetchPosts(newer) {
|
||||
const { graph, graphResource, api } = this.props;
|
||||
const { graph, graphPath, api } = this.props;
|
||||
const graphResource = resourceFromPath(graphPath);
|
||||
|
||||
if (this.isFetching) {
|
||||
return false;
|
||||
@ -134,11 +131,12 @@ export class PostFeed extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { graph, pendingSize, parentNode } = this.props;
|
||||
const { graph, pendingSize, parentNode, history } = this.props;
|
||||
|
||||
return (
|
||||
<Col width="100%" height="100%" position="relative">
|
||||
<VirtualScroller
|
||||
key={history.location.pathname}
|
||||
origin="top"
|
||||
offset={0}
|
||||
data={graph}
|
||||
|
@ -7,10 +7,12 @@ import tokenizeMessage from '~/logic/lib/tokenizeMessage';
|
||||
import { useToggleState } from '~/logic/lib/useToggleState';
|
||||
import { createPost } from '~/logic/api/graph';
|
||||
import useStorage from '~/logic/lib/useStorage';
|
||||
import { resourceFromPath } from '~/logic/lib/group';
|
||||
|
||||
|
||||
export function PostInput(props) {
|
||||
const { api, graphResource, index, submitCallback } = props;
|
||||
const { api, graphPath, index, submitCallback } = props;
|
||||
const graphResource = resourceFromPath(graphPath);
|
||||
|
||||
const [disabled, setDisabled] = useState(false);
|
||||
const [code, toggleCode] = useToggleState(false);
|
||||
|
@ -1,10 +1,13 @@
|
||||
import React from 'react';
|
||||
import { Col } from '@tlon/indigo-react';
|
||||
import { MentionText } from '~/views/components/MentionText';
|
||||
import useContactState from '~/logic/state/contact';
|
||||
|
||||
|
||||
export function PostContent(props) {
|
||||
const { post, contacts, isParent, api } = props;
|
||||
const { post, isParent, api } = props;
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
|
||||
return (
|
||||
<Col
|
||||
width="100%"
|
@ -4,11 +4,12 @@ import Author from '~/views/components/Author';
|
||||
import { useCopy } from '~/logic/lib/useCopy';
|
||||
import { getPermalinkForGraph } from '~/logic/lib/permalinks';
|
||||
import { Dropdown } from '~/views/components/Dropdown';
|
||||
|
||||
import useContactState from '~/logic/state/contact';
|
||||
|
||||
|
||||
export function PostHeader(props) {
|
||||
const { post, contacts, api, association, isReply } = props;
|
||||
const { post, api, association, isReply } = props;
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
const mb = isReply ? "2" : "3";
|
||||
|
||||
const permalink = !!association ? getPermalinkForGraph(
|
@ -3,10 +3,11 @@ import { Box, Col, Row, Text } from '@tlon/indigo-react';
|
||||
import { PostHeader } from './PostHeader';
|
||||
import { PostContent } from './PostContent';
|
||||
import { PostFooter } from './PostFooter';
|
||||
import { PostInput } from './PostInput';
|
||||
import { PostInput } from '../PostInput';
|
||||
import { Mention } from "~/views/components/MentionText";
|
||||
import withState from '~/logic/lib/withState';
|
||||
import { useHovering } from '~/logic/lib/util';
|
||||
import { resourceFromPath } from '~/logic/lib/group';
|
||||
|
||||
|
||||
class PostItem extends React.Component {
|
||||
@ -43,9 +44,8 @@ class PostItem extends React.Component {
|
||||
render() {
|
||||
const {
|
||||
node,
|
||||
contacts,
|
||||
api,
|
||||
graphResource,
|
||||
graphPath,
|
||||
association,
|
||||
index,
|
||||
innerRef,
|
||||
@ -55,6 +55,7 @@ class PostItem extends React.Component {
|
||||
hovering,
|
||||
bind
|
||||
} = this.props;
|
||||
const graphResource = resourceFromPath(graphPath);
|
||||
|
||||
let indexString = '';
|
||||
|
||||
@ -85,7 +86,6 @@ class PostItem extends React.Component {
|
||||
{...bind}>
|
||||
<PostHeader
|
||||
post={node.post}
|
||||
contacts={contacts}
|
||||
api={api}
|
||||
association={association}
|
||||
isReply={isReply} />
|
||||
@ -98,8 +98,7 @@ class PostItem extends React.Component {
|
||||
<PostContent
|
||||
post={node.post}
|
||||
isParent={isParent}
|
||||
api={api}
|
||||
contacts={contacts} />
|
||||
api={api} />
|
||||
<PostFooter
|
||||
replyCount={node.children.size}
|
||||
toggleReplyMode={this.toggleReplyMode} />
|
||||
@ -113,7 +112,7 @@ class PostItem extends React.Component {
|
||||
borderLeftColor="lightGray"></Box>
|
||||
<PostInput
|
||||
api={api}
|
||||
graphResource={graphResource}
|
||||
graphPath={graphPath}
|
||||
index={indexString}
|
||||
submitCallback={this.submitCallback} />
|
||||
</Col>
|
@ -2,26 +2,28 @@ import React from 'react';
|
||||
import bigInt from 'big-integer';
|
||||
import { Text, Col, Box } from '@tlon/indigo-react'
|
||||
import { PostInput } from './PostInput';
|
||||
import PostItem from './PostItem';
|
||||
import PostItem from './PostItem/PostItem';
|
||||
import { PostFeed } from './PostFeed';
|
||||
import { Loading } from '~/views/components/Loading';
|
||||
import { resourceFromPath } from '~/logic/lib/group';
|
||||
|
||||
|
||||
export function PostReplies(props) {
|
||||
export default function PostReplies(props) {
|
||||
const {
|
||||
baseUrl,
|
||||
api,
|
||||
history,
|
||||
association,
|
||||
groups,
|
||||
contacts,
|
||||
graphPath,
|
||||
graphs,
|
||||
pendingSize,
|
||||
graphResource
|
||||
pendingSize
|
||||
} = props;
|
||||
|
||||
const graphResource = resourceFromPath(graphPath);
|
||||
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
|
||||
const shouldRenderFeed = graphId in graphs;
|
||||
|
||||
let graph = props.graph;
|
||||
const shouldRenderFeed = !!graph;
|
||||
|
||||
if (!shouldRenderFeed) {
|
||||
return (
|
||||
@ -32,13 +34,12 @@ export function PostReplies(props) {
|
||||
}
|
||||
|
||||
const locationUrl =
|
||||
history.location.pathname.replace(`${baseUrl}/feed`, '');
|
||||
props.locationUrl.replace(`${baseUrl}/feed`, '');
|
||||
let nodeIndex = locationUrl.split('/').slice(1).map((ind) => {
|
||||
return bigInt(ind);
|
||||
});
|
||||
|
||||
let node;
|
||||
let graph = graphs[graphId];
|
||||
nodeIndex.forEach((i) => {
|
||||
if (!graph) {
|
||||
return null;
|
||||
@ -58,7 +59,7 @@ export function PostReplies(props) {
|
||||
if (!first) {
|
||||
return (
|
||||
<Col
|
||||
key={0}
|
||||
key={locationUrl}
|
||||
width="100%"
|
||||
height="100%"
|
||||
alignItems="center" overflowY="scroll">
|
||||
@ -66,8 +67,7 @@ export function PostReplies(props) {
|
||||
<PostItem
|
||||
key={node.post.index}
|
||||
node={node}
|
||||
contacts={contacts}
|
||||
graphResource={graphResource}
|
||||
graphPath={graphPath}
|
||||
association={association}
|
||||
api={api}
|
||||
index={nodeIndex}
|
||||
@ -96,13 +96,12 @@ export function PostReplies(props) {
|
||||
<Box height="calc(100% - 48px)" width="100%" alignItems="center" pl="1" pt="3">
|
||||
<PostFeed
|
||||
key={locationUrl}
|
||||
graphResource={graphResource}
|
||||
graphPath={graphPath}
|
||||
graph={graph}
|
||||
parentNode={node}
|
||||
pendingSize={pendingSize}
|
||||
association={association}
|
||||
groups={groups}
|
||||
contacts={contacts}
|
||||
api={api}
|
||||
history={history}
|
||||
baseUrl={baseUrl}
|
||||
|
@ -3,23 +3,21 @@ import { Text, Col, Box } from '@tlon/indigo-react'
|
||||
import { PostInput } from './PostInput';
|
||||
import { PostFeed } from './PostFeed';
|
||||
import { Loading } from '~/views/components/Loading';
|
||||
import { resourceFromPath } from '~/logic/lib/group';
|
||||
|
||||
|
||||
export function PostTimeline(props) {
|
||||
export default function PostTimeline(props) {
|
||||
const {
|
||||
baseUrl,
|
||||
api,
|
||||
history,
|
||||
association,
|
||||
groups,
|
||||
contacts,
|
||||
graphPath,
|
||||
graphs,
|
||||
graph,
|
||||
pendingSize,
|
||||
graphResource
|
||||
} = props;
|
||||
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
|
||||
const shouldRenderFeed = graphId in graphs;
|
||||
const graphResource = resourceFromPath(graphPath);
|
||||
const shouldRenderFeed = !!graph;
|
||||
|
||||
if (!shouldRenderFeed) {
|
||||
return (
|
||||
@ -29,7 +27,6 @@ export function PostTimeline(props) {
|
||||
);
|
||||
}
|
||||
|
||||
const graph = graphs[graphId];
|
||||
const first = graph.peekLargest()?.[0];
|
||||
if (!first) {
|
||||
return (
|
||||
@ -48,7 +45,7 @@ export function PostTimeline(props) {
|
||||
alignItems="center">
|
||||
<PostInput
|
||||
api={api}
|
||||
graphResource={graphResource} />
|
||||
graphPath={graphPath} />
|
||||
</Col>
|
||||
<Box
|
||||
pl="2"
|
||||
@ -77,17 +74,15 @@ export function PostTimeline(props) {
|
||||
mb="3"
|
||||
flexDirection="column"
|
||||
alignItems="center">
|
||||
<PostInput api={api} graphResource={graphResource} />
|
||||
<PostInput api={api} graphPath={graphPath} />
|
||||
</Box>
|
||||
<Box height="calc(100% - 176px)" width="100%" alignItems="center" pl="1">
|
||||
<PostFeed
|
||||
key={graphPath}
|
||||
graphResource={graphResource}
|
||||
graph={graphs[graphId]}
|
||||
graphPath={graphPath}
|
||||
graph={graph}
|
||||
pendingSize={pendingSize}
|
||||
association={association}
|
||||
groups={groups}
|
||||
contacts={contacts}
|
||||
api={api}
|
||||
history={history}
|
||||
baseUrl={baseUrl}
|
||||
|
@ -21,6 +21,7 @@ import useGraphState from '~/logic/state/graph';
|
||||
import useHarkState, { withHarkState } from '~/logic/state/hark';
|
||||
import withState from '~/logic/lib/withState';
|
||||
|
||||
|
||||
type LandscapeProps = StoreState & {
|
||||
ship: PatpNoSig;
|
||||
api: GlobalApi;
|
||||
@ -67,95 +68,85 @@ export function DMRedirect(props: LandscapeProps & RouteComponentProps & { ship:
|
||||
);
|
||||
}
|
||||
|
||||
class Landscape extends Component<LandscapeProps, Record<string, never>> {
|
||||
componentDidMount(): void {
|
||||
this.props.subscription.startApp('groups');
|
||||
this.props.subscription.startApp('graph');
|
||||
}
|
||||
export default function Landscape(props) {
|
||||
const notificationsCount = useHarkState(s => s.notificationsCount);
|
||||
|
||||
render(): ReactElement {
|
||||
const { props } = this;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet defer={false}>
|
||||
<title>{ props.notificationsCount ? `(${String(props.notificationsCount) }) `: '' }Landscape</title>
|
||||
</Helmet>
|
||||
<Switch>
|
||||
<Route path="/~landscape/ship/:host/:name"
|
||||
render={(routeProps) => {
|
||||
const {
|
||||
host,
|
||||
name
|
||||
} = routeProps.match.params as Record<string, string>;
|
||||
const groupPath = `/ship/${host}/${name}`;
|
||||
const baseUrl = `/~landscape${groupPath}`;
|
||||
const ws: Workspace = { type: 'group', group: groupPath };
|
||||
|
||||
return (
|
||||
<GroupsPane workspace={ws} baseUrl={baseUrl} {...props} />
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route path="/~landscape/home"
|
||||
render={() => {
|
||||
const ws: Workspace = { type: 'home' };
|
||||
return (
|
||||
<GroupsPane workspace={ws} baseUrl="/~landscape/home" {...props} />
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route path="/~landscape/messages"
|
||||
render={() => {
|
||||
const ws: Workspace = { type: 'messages' };
|
||||
return (
|
||||
<GroupsPane workspace={ws} baseUrl="/~landscape/messages" {...props} />
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route path="/~landscape/new"
|
||||
render={(routeProps) => {
|
||||
return (
|
||||
<Body>
|
||||
<Box maxWidth="300px">
|
||||
<NewGroup
|
||||
api={props.api}
|
||||
{...routeProps}
|
||||
/>
|
||||
</Box>
|
||||
</Body>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route path='/~landscape/dm/:ship?'
|
||||
return (
|
||||
<>
|
||||
<Helmet defer={false}>
|
||||
<title>{ props.notificationsCount ? `(${String(props.notificationsCount) }) `: '' }Landscape</title>
|
||||
</Helmet>
|
||||
<Switch>
|
||||
<Route path="/~landscape/ship/:host/:name"
|
||||
render={(routeProps) => {
|
||||
const { ship } = routeProps.match.params;
|
||||
return <DMRedirect {...routeProps} {...props} ship={ship} />;
|
||||
const {
|
||||
host,
|
||||
name
|
||||
} = routeProps.match.params as Record<string, string>;
|
||||
const groupPath = `/ship/${host}/${name}`;
|
||||
const baseUrl = `/~landscape${groupPath}`;
|
||||
const ws: Workspace = { type: 'group', group: groupPath };
|
||||
|
||||
return (
|
||||
<GroupsPane workspace={ws} baseUrl={baseUrl} {...props} />
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route path="/~landscape/join/:ship?/:name?"
|
||||
render={(routeProps) => {
|
||||
const { ship, name } = routeProps.match.params;
|
||||
const autojoin = ship && name ? `${ship}/${name}` : undefined;
|
||||
return (
|
||||
<Body>
|
||||
<Box maxWidth="300px">
|
||||
<JoinGroup
|
||||
api={props.api}
|
||||
autojoin={autojoin}
|
||||
{...routeProps}
|
||||
/>
|
||||
</Box>
|
||||
</Body>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
}
|
||||
/>
|
||||
<Route path="/~landscape/home"
|
||||
render={() => {
|
||||
const ws: Workspace = { type: 'home' };
|
||||
return (
|
||||
<GroupsPane workspace={ws} baseUrl="/~landscape/home" {...props} />
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route path="/~landscape/messages"
|
||||
render={() => {
|
||||
const ws: Workspace = { type: 'messages' };
|
||||
return (
|
||||
<GroupsPane workspace={ws} baseUrl="/~landscape/messages" {...props} />
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route path="/~landscape/new"
|
||||
render={(routeProps) => {
|
||||
return (
|
||||
<Body>
|
||||
<Box maxWidth="300px">
|
||||
<NewGroup
|
||||
api={props.api}
|
||||
{...routeProps}
|
||||
/>
|
||||
</Box>
|
||||
</Body>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route path='/~landscape/dm/:ship?'
|
||||
render={(routeProps) => {
|
||||
const { ship } = routeProps.match.params;
|
||||
return <DMRedirect {...routeProps} {...props} ship={ship} />;
|
||||
}}
|
||||
/>
|
||||
<Route path="/~landscape/join/:ship?/:name?"
|
||||
render={(routeProps) => {
|
||||
const { ship, name } = routeProps.match.params;
|
||||
const autojoin = ship && name ? `${ship}/${name}` : undefined;
|
||||
return (
|
||||
<Body>
|
||||
<Box maxWidth="300px">
|
||||
<JoinGroup
|
||||
api={props.api}
|
||||
autojoin={autojoin}
|
||||
{...routeProps}
|
||||
/>
|
||||
</Box>
|
||||
</Body>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default withState(Landscape, [
|
||||
[useHarkState, ['notificationsCount']]
|
||||
]);
|
||||
|
Loading…
Reference in New Issue
Block a user