Merge pull request #4975 from urbit/lf/more-buses

interface: post-deploy fix omnibus
This commit is contained in:
matildepark 2021-06-03 01:51:32 -04:00 committed by GitHub
commit 6a23722448
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 140 additions and 53 deletions

View File

@ -62,8 +62,8 @@ export function getNotificationKey(
): string {
const base = time.toString();
if ('graph' in notification.index) {
const { graph, index } = notification.index.graph;
return `${base}-${graph}-${index}`;
const { graph, index, description } = notification.index.graph;
return `${base}-${graph}-${index}-${description}`;
} else if ('group' in notification.index) {
const { group } = notification.index.group;
return `${base}-${group}`;

View File

@ -4,7 +4,6 @@ import {
Timebox
} from '@urbit/api';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import { BigInteger } from 'big-integer';
import _ from 'lodash';
import { compose } from 'lodash/fp';
import { makePatDa } from '~/logic/lib/util';
@ -152,7 +151,9 @@ function unreads(json: any, state: HarkState): HarkState {
const { unreads, notifications, last } = stats;
updateNotificationStats(state, index, 'last', () => last);
_.each(notifications, ({ time, index }) => {
addNotificationToUnread(state, index, makePatDa(time));
if(!time) {
addNotificationToUnread(state, index);
}
});
if('count' in unreads) {
updateUnreadCount(state, index, (u = 0) => u + unreads.count);
@ -210,14 +211,16 @@ function updateUnreads(state: HarkState, index: NotifIndex, f: (us: Set<string>)
return state;
}
function addNotificationToUnread(state: HarkState, index: NotifIndex, time: BigInteger) {
function addNotificationToUnread(state: HarkState, index: NotifIndex) {
if('graph' in index) {
const path = [index.graph.graph, index.graph.index, 'notifications'];
const curr = _.get(state.unreads.graph, path, []);
_.set(state.unreads.graph, path,
[
...curr.filter(c => !(c.time.eq(time) && notifIdxEqual(c.index, index))),
{ time, index }
...curr.filter((c) => {
return !(notifIdxEqual(c.index, index));
}),
{ index }
]
);
} else if ('group' in index) {
@ -225,12 +228,23 @@ function addNotificationToUnread(state: HarkState, index: NotifIndex, time: BigI
const curr = _.get(state.unreads.group, path, []);
_.set(state.unreads.group, path,
[
...curr.filter(c => !(c.time.eq(time) && notifIdxEqual(c.index, index))),
{ time, index }
...curr.filter(c => !notifIdxEqual(c.index, index)),
{ index }
]
);
}
}
function removeNotificationFromUnread(state: HarkState, index: NotifIndex) {
if('graph' in index) {
const path = [index.graph.graph, index.graph.index, 'notifications'];
const curr = _.get(state.unreads.graph, path, []);
_.set(state.unreads.graph, path, curr.filter(c => !notifIdxEqual(c.index, index)));
} else if ('group' in index) {
const path = [index.group.group, 'notifications'];
const curr = _.get(state.unreads.group, path, []);
_.set(state.unreads.group, path, curr.filter(c => !notifIdxEqual(c.index, index)));
}
}
function updateNotificationStats(state: HarkState, index: NotifIndex, statField: 'unreads' | 'last', f: (x: number) => number, notify = false) {
if('graph' in index) {
@ -280,6 +294,9 @@ const timebox = (json: any, state: HarkState): HarkState => {
state.notifications = state.notifications.set(time, data.notifications);
} else {
state.unreadNotes = data.notifications;
_.each(data.notifications, ({ index }) => {
addNotificationToUnread(state, index);
});
}
}
return state;
@ -338,6 +355,7 @@ function read(json: any, state: HarkState): HarkState {
read[0].notification.contents = mergeNotifs(read[0].notification.contents, toMerge[0].notification.contents);
}
state.notifications = state.notifications.set(time, [...read, ...rest]);
removeNotificationFromUnread(state, index);
}
return state;
}
@ -364,6 +382,7 @@ function archive(json: any, state: HarkState): HarkState {
}
} else {
state.unreadNotes = state.unreadNotes.filter(({ index: idx }) => !notifIdxEqual(idx, index));
removeNotificationFromUnread(state, index);
}
}
return state;

View File

@ -54,7 +54,12 @@ Omnibus.args = {
{ mention: 'sipfyn-pidmex' },
{ text: `: you can always use a pattern like this
> blockquote demo
should not be quoted` }
should not be quoted
> blockquote, then newline, then mention
` },
{ mention: '~sampel-palnet' },
{ text: '> mention inside blockquote' },
{ mention: '~sampel-palnet' }
]
};

View File

@ -0,0 +1,17 @@
import React from 'react';
import { Meta } from '@storybook/react';
import { Box } from '@tlon/indigo-react';
import { PendingDm } from '~/views/apps/notifications/PendingDm';
export default {
title: 'Notifications/PendingDm',
component: PendingDm
} as Meta;
const fakeApi = {} as any;
export const Default = () => (
<Box width="95%" p="1" backgroundColor="white">
<PendingDm api={fakeApi} ship="~hastuc-dibtux" />
</Box>
);

View File

@ -1,5 +1,6 @@
import { cite, Content } from '@urbit/api';
import { cite, Content, Post } from '@urbit/api';
import React, { useCallback, useEffect } from 'react';
import _ from 'lodash';
import bigInt from 'big-integer';
import { Box, Row, Col, Text } from '@tlon/indigo-react';
import { Link } from 'react-router-dom';
@ -27,6 +28,27 @@ const getCurrDmSize = (ship: string) => {
return shipGraph?.children?.size ?? 0;
};
function quoteReply(post: Post) {
const reply = _.reduce(
post.contents,
(acc, content) => {
if ('text' in content) {
return `${acc}${content.text}`;
} else if ('url' in content) {
return `${acc}${content.url}`;
} else if ('mention' in content) {
return `${acc}${content.mention}`;
}
return acc;
},
''
)
.split('\n')
.map(l => `> ${l}`)
.join('\n');
return `${reply}\n\n~${post.author}:`;
}
export function DmResource(props: DmResourceProps) {
const { ship, api } = props;
const dm = useDM(ship);
@ -38,7 +60,12 @@ export function DmResource(props: DmResourceProps) {
const nickname = showNickname ? contact!.nickname : cite(ship) ?? ship;
useEffect(() => {
api.graph.getNewest(`~${window.ship}`, 'dm-inbox', 100, `/${patpToUd(ship)}`);
api.graph.getNewest(
`~${window.ship}`,
'dm-inbox',
100,
`/${patpToUd(ship)}`
);
}, [ship]);
const fetchMessages = useCallback(
@ -75,7 +102,10 @@ export function DmResource(props: DmResourceProps) {
);
const dismissUnread = useCallback(() => {
api.hark.dismissReadCount(`/ship/~${window.ship}/dm-inbox`, `/${patp2dec(ship)}`);
api.hark.dismissReadCount(
`/ship/~${window.ship}/dm-inbox`,
`/${patp2dec(ship)}`
);
}, [ship]);
const onSubmit = useCallback(
@ -99,13 +129,13 @@ export function DmResource(props: DmResourceProps) {
<Row alignItems="baseline">
<Box
borderRight={1}
borderRightColor='gray'
borderRightColor="gray"
pr={3}
fontSize={1}
mr={3}
my={1}
flexShrink={0}
display={['block','none']}
display={['block', 'none']}
>
<Link to={'/~landscape/messages'}>
<Text>{'<- Back'}</Text>
@ -131,10 +161,10 @@ export function DmResource(props: DmResourceProps) {
id={ship}
graph={dm}
unreadCount={unreadCount}
onReply={() => ''}
onReply={quoteReply}
fetchMessages={fetchMessages}
dismissUnread={dismissUnread}
getPermalink={() => ''}
getPermalink={() => undefined}
isAdmin
onSubmit={onSubmit}
/>

View File

@ -329,9 +329,11 @@ const MessageActions = ({ onReply, onDelete, msg, isAdmin, permalink }) => {
<MessageActionItem onClick={() => onReply(msg)}>
Reply
</MessageActionItem>
<MessageActionItem onClick={doCopy}>
{copyDisplay}
</MessageActionItem>
{permalink ? (
<MessageActionItem onClick={doCopy}>
{copyDisplay}
</MessageActionItem>
) : null }
{(isAdmin || isOwn()) ? (
<MessageActionItem onClick={e => onDelete(msg)} color='red'>
Delete Message

View File

@ -25,7 +25,7 @@ type ChatWindowProps = {
dismissUnread: () => void;
pendingSize?: number;
showOurContact: boolean;
getPermalink: (index: BigInteger) => string;
getPermalink: (index: BigInteger) => string | undefined;
isAdmin: boolean;
};
@ -208,7 +208,7 @@ class ChatWindow extends Component<
This message has been deleted.
</Text>
);
};
}
if (!this.state.initialized) {
return (
<MessagePlaceholder
@ -239,7 +239,7 @@ class ChatWindow extends Component<
};
return (
// @ts-ignore
// @ts-ignore virt typings
<ChatMessage
key={index.toString()}
ref={ref}

View File

@ -1,5 +1,5 @@
import React, { useCallback } from 'react';
import { Box, Col, Row, Text } from '@tlon/indigo-react';
import { Box, Row, Text } from '@tlon/indigo-react';
import { StatelessAsyncAction } from '~/views/components/StatelessAsyncAction';
import Author from '~/views/components/Author';
import GlobalApi from '~/logic/api/global';
@ -23,8 +23,12 @@ export function PendingDm(props: { ship: string; api: GlobalApi }) {
bg="washedGray"
borderRadius="2"
gridTemplateColumns={['1fr 24px', '1fr 200px']}
gridRowGap={2}
gridTemplateRows="auto"
gridTemplateAreas="'header actions' 'main main'"
gridTemplateAreas={[
'\'header header\' \'actions actions\'',
'\'header actions\' \'main main\''
]}
p={2}
m={2}
>
@ -40,10 +44,17 @@ export function PendingDm(props: { ship: string; api: GlobalApi }) {
gridArea="actions"
justifyContent="flex-end"
>
<StatelessAsyncAction height="auto" primary p="1" onClick={onAccept}>
<StatelessAsyncAction
backgroundColor="white"
height="auto"
primary
p="1"
onClick={onAccept}
>
Accept
</StatelessAsyncAction>
<StatelessAsyncAction
backgroundColor="white"
height="auto"
destructive
p="1"

View File

@ -97,13 +97,13 @@ export const GraphNodeContent = ({ post, mod, index, hidden, association }) => {
const { contents } = post;
const idx = index.slice(1).split('/');
const url = getNodeUrl(mod, hidden, association?.group, association?.resource, index);
if (mod === 'link' && idx.length === 1) {
if (mod === 'graph-validator-link' && idx.length === 1) {
const [{ text: title }] = contents;
return (
<ContentSummary to={url} icon="Links" name={title} author={post.author} />
);
}
if (mod === 'publish' && idx[1] === '1') {
if (mod === 'graph-validator-publish' && idx[1] === '1') {
const [{ text: title }] = contents;
return (
<ContentSummary to={url} icon="Note" name={title} author={post.author} />
@ -251,23 +251,16 @@ export function GraphNotification(props: {
history.push(`/~landscape/messages/dm/~${authors[0]}`);
return;
}
if (
!(
(index.description === 'note' || index.description === 'link') &&
index.index === '/'
const first = contents[0];
history.push(
getNodeUrl(
index.mark,
groups[association?.group]?.hidden,
association?.group,
association?.resource,
first.index
)
) {
const first = contents[0];
history.push(
getNodeUrl(
index.mark,
groups[association?.group]?.hidden,
association?.group,
association?.resource,
first.index
)
);
}
);
}, [api, timebox, index, read, history.push, authors, dm]);
const authorsInHeader =

View File

@ -156,7 +156,7 @@ const ProfileOverlay = (props: ProfileOverlayProps) => {
icon='Chat'
size={16}
cursor='pointer'
onClick={() => history.push(`/~landscape/messages/dm/${ship}`)}
onClick={() => history.push(`/~landscape/messages/dm/~${ship}`)}
/>
)}
</Row>

View File

@ -100,9 +100,9 @@ export function Omnibox(props: OmniboxProps): ReactElement {
}
Mousetrap.bind('escape', props.toggle);
const touchstart = new Event('touchstart');
// @ts-ignore
// @ts-ignore ref typings
inputRef?.current?.input?.dispatchEvent(touchstart);
// @ts-ignore
// @ts-ignore ref typings
inputRef?.current?.input?.focus();
return () => {
Mousetrap.unbind('escape');
@ -150,7 +150,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
}, [query, index]);
const navigate = useCallback(
(app: string, link: string) => {
(app: string, link: string, shift: boolean) => {
props.toggle();
if (
defaultApps.includes(app.toLowerCase()) ||
@ -162,6 +162,10 @@ export function Omnibox(props: OmniboxProps): ReactElement {
app === 'home' ||
app === 'inbox'
) {
if(shift && app === 'profile') {
// TODO: hacky, fix
link = link.replace('~profile', '~landscape/messages/dm');
}
history.push(link);
} else {
window.location.href = link;
@ -246,13 +250,14 @@ export function Omnibox(props: OmniboxProps): ReactElement {
if (evt.key === 'Enter') {
evt.preventDefault();
if (selected.length) {
navigate(selected[0], selected[1]);
navigate(selected[0], selected[1], evt.shiftKey);
} else if (Array.from(results.values()).flat().length === 0) {
return;
} else {
navigate(
Array.from(results.values()).flat()[0].app,
Array.from(results.values()).flat()[0].link
Array.from(results.values()).flat()[0].link,
evt.shiftKey
);
}
}
@ -335,7 +340,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
subtext={result.host}
link={result.link}
cursor={leapCursor}
navigate={() => navigate(result.app, result.link)}
navigate={() => navigate(result.app, result.link, false)}
setSelection={() => setSelection(result.app, result.link)}
selected={sel}
/>

View File

@ -122,6 +122,7 @@ function stitchInline(a: any, b: any) {
}
const lastParaIdx = a.children.length - 1;
const last = a.children[lastParaIdx];
console.log(last);
if (last?.children) {
const ros = {
...a,

View File

@ -1,3 +1,4 @@
/* eslint-disable */
/** pulled from remark-parse
*
* critical change is that blockquotes require a newline to be continued, see
@ -106,6 +107,7 @@ function blockquote(eat, value, silent) {
index = nextIndex + 1
}
const trailingNewline = value.charAt(nextIndex) === '\n';
index = -1
length = indents.length
@ -118,7 +120,9 @@ function blockquote(eat, value, silent) {
exit = self.enterBlock()
contents = self.tokenizeBlock(contents.join(lineFeed), now)
console.log(values);
exit()
return add({type: 'blockquote', children: contents})
const added = add({type: 'blockquote', children: contents})
return trailingNewline ? add({ type: 'paragraph', children: [] }) : added;
}

View File

@ -6,7 +6,7 @@ function lineBreak(eat, value: string, silent) {
while(++index < length ) {
character = value.charAt(index);
if(character === '\n') {
eat(character)({ type : 'break' });
eat(character)({ type: 'paragraph', contents: [{ type: 'break' }] });
} else {
return;
}