From 5e1c03ca9c0f52b63aa2b51cb1779b148bc441b7 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 2 Jul 2021 09:53:36 +1000 Subject: [PATCH 01/11] interface: fix malformed group links in tokenisation Fixes urbit/landscape#1020 --- pkg/interface/src/logic/lib/tokenizeMessage.js | 5 +++-- pkg/interface/src/logic/lib/tokenizeMessage.test.js | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pkg/interface/src/logic/lib/tokenizeMessage.js b/pkg/interface/src/logic/lib/tokenizeMessage.js index 941742328..6071d5843 100644 --- a/pkg/interface/src/logic/lib/tokenizeMessage.js +++ b/pkg/interface/src/logic/lib/tokenizeMessage.js @@ -33,9 +33,10 @@ const raceRegexes = (str) => { content = { url: link[2] }; } } - if(groupRef && groupRef[1].length < pfix?.length) { + let perma = parsePermalink(convertToGroupRef(groupRef?.[2])); + const [,,host] = perma?.group.split('/') ?? []; + if(groupRef && groupRef[1].length < pfix?.length && !!perma && urbitOb.isValidPatp(host)) { pfix = groupRef[1]; - const perma = parsePermalink(convertToGroupRef(groupRef[2])); content = permalinkToReference(perma); sfix = groupRef[3]; } diff --git a/pkg/interface/src/logic/lib/tokenizeMessage.test.js b/pkg/interface/src/logic/lib/tokenizeMessage.test.js index 835c9e71b..9958e93e2 100644 --- a/pkg/interface/src/logic/lib/tokenizeMessage.test.js +++ b/pkg/interface/src/logic/lib/tokenizeMessage.test.js @@ -113,4 +113,10 @@ describe('tokenizeMessage', () => { expect(text).toBe('. foo'); expect(url).toBe('https://tlon.io/test'); }); + + it('should ignore malformed group links', () => { + const example = 'test ~zoid/fakegroup'; + const [{ text }, ...rest] = tokenizeMessage(example); + expect(text).toBe(example); + }); }); From 604abff7693942fc1ee383a706e44ef8ed04631a Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 2 Jul 2021 09:56:10 +1000 Subject: [PATCH 02/11] RemoteContent: fixed mixed content failure on embeds --- pkg/interface/src/logic/state/embed.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/interface/src/logic/state/embed.tsx b/pkg/interface/src/logic/state/embed.tsx index 4911d00a0..3edd9bbb6 100644 --- a/pkg/interface/src/logic/state/embed.tsx +++ b/pkg/interface/src/logic/state/embed.tsx @@ -11,7 +11,7 @@ export interface EmbedState { fetch: (url: string) => Promise; } -const OEMBED_PROVIDER = 'http://noembed.com/embed'; +const OEMBED_PROVIDER = 'https://noembed.com/embed'; const useEmbedState = create((set, get) => ({ embeds: {}, From 8cdda7c1f463d8cf2d01dedbeae8741b8519a42a Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 2 Jul 2021 14:12:05 +1000 Subject: [PATCH 03/11] LinkDetail: fix safari styling --- pkg/interface/src/views/apps/links/components/LinkDetail.tsx | 2 +- pkg/interface/src/views/components/RemoteContent/embed.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/interface/src/views/apps/links/components/LinkDetail.tsx b/pkg/interface/src/views/apps/links/components/LinkDetail.tsx index d6640ef53..539ec0d9b 100644 --- a/pkg/interface/src/views/apps/links/components/LinkDetail.tsx +++ b/pkg/interface/src/views/apps/links/components/LinkDetail.tsx @@ -21,7 +21,7 @@ export function LinkDetail(props: LinkDetailProps) { return ( /* @ts-ignore indio props?? */ - + Date: Fri, 2 Jul 2021 14:13:06 +1000 Subject: [PATCH 04/11] interface: add more collections stories, fix test flake --- .../src/stories/LinkBlockItem.stories.tsx | 11 ++-- .../src/stories/LinkDetail.stories.tsx | 63 +++++++++++++++++-- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/pkg/interface/src/stories/LinkBlockItem.stories.tsx b/pkg/interface/src/stories/LinkBlockItem.stories.tsx index b3178109d..927712e17 100644 --- a/pkg/interface/src/stories/LinkBlockItem.stories.tsx +++ b/pkg/interface/src/stories/LinkBlockItem.stories.tsx @@ -22,6 +22,7 @@ export const Image = () => ( ( /> ( - - + + ); @@ -75,6 +75,7 @@ Fallback.parameters = { export const Audio = () => ( ( ().gas([ makeComment( 'ridlur-figbud', - moment().hour(12).minute(34).valueOf(), + Date.now() - 4*HOUR, nodeIndex, [{ text: 'Beautiful' }] ), makeComment( 'roslet-tanner', - moment().hour(12).minute(34).valueOf(), + Date.now() - 3*HOUR, nodeIndex, [{ text: 'where did you find this?' }] ), makeComment( 'fabled-faster', - moment().hour(12).minute(34).valueOf(), + Date.now() - 2*HOUR, + nodeIndex, + [{ text: 'I dont\'t remember lol' }] + ) + ]) +}; + +const youtubeNode = { + post: { + index: '/170141184504850861030994857749504231212', + author: 'fabled-faster', + 'time-sent': 1609969377513, + signatures: [], + contents: [ + { text: 'LindyMan' }, + { + url: 'https://twitter.com/PaulSkallas/status/1388896550198317056' + } + ], + hash: null + }, + children: new BigIntOrderedMap().gas([ + makeComment( + 'ridlur-figbud', + Date.now() - 4*HOUR, + nodeIndex, + [{ text: 'Beautiful' }] + ), + makeComment( + 'roslet-tanner', + Date.now() - 3*HOUR, + nodeIndex, + [{ text: 'where did you find this?' }] + ), + + makeComment( + 'fabled-faster', + Date.now() - 2*HOUR, nodeIndex, [{ text: 'I dont\'t remember lol' }] ) @@ -60,7 +98,7 @@ export const Image = () => { s => s.associations.graph['/ship/~bitbet-bolbel/links'] ); return ( - + { ); }; + +export const Youtube = () => { + const association = useMetadataState( + s => s.associations.graph['/ship/~bitbet-bolbel/links'] + ); + return ( + + + + ); +}; Image.parameters = { design: { type: 'figma', From 6b7030d617091ced3ad1ef08ac74f62fcfe3e193 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 2 Jul 2021 15:42:17 +1000 Subject: [PATCH 05/11] interface: omnibox go fast --- .../src/views/components/leap/Omnibox.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pkg/interface/src/views/components/leap/Omnibox.tsx b/pkg/interface/src/views/components/leap/Omnibox.tsx index c2500bf70..d50cbdeb0 100644 --- a/pkg/interface/src/views/components/leap/Omnibox.tsx +++ b/pkg/interface/src/views/components/leap/Omnibox.tsx @@ -1,6 +1,8 @@ import { Box, Row, Text } from '@tlon/indigo-react'; import { omit } from 'lodash'; import Mousetrap from 'mousetrap'; +import _ from 'lodash'; +import f from 'lodash/fp'; import React, { ReactElement, useCallback, useEffect, useMemo, @@ -41,6 +43,7 @@ const SEARCHED_CATEGORIES = [ 'apps' ]; const settingsSel = (s: SettingsState) => s.leap; +const CAT_LIMIT = 6; export function Omnibox(props: OmniboxProps): ReactElement { const location = useLocation(); @@ -175,7 +178,7 @@ export function Omnibox(props: OmniboxProps): ReactElement { ); const setPreviousSelected = useCallback(() => { - const flattenedResults = Array.from(results.values()).flat(); + const flattenedResults = Array.from(results.values()).map(f.take(CAT_LIMIT)).flat(); const totalLength = flattenedResults.length; if (selected.length) { const currentIndex = flattenedResults.indexOf( @@ -198,7 +201,7 @@ export function Omnibox(props: OmniboxProps): ReactElement { }, [results, selected]); const setNextSelected = useCallback(() => { - const flattenedResults = Array.from(results.values()).flat(); + const flattenedResults = Array.from(results.values()).map(f.take(CAT_LIMIT)).flat(); if (selected.length) { const currentIndex = flattenedResults.indexOf( // @ts-ignore unclear how to give this spread a return signature @@ -309,13 +312,15 @@ export function Omnibox(props: OmniboxProps): ReactElement { return ( {SEARCHED_CATEGORIES.map(category => - Object({ category, categoryResults: results.get(category) }) + Object({ + category, + categoryResults: _.take(results.get(category).sort(sortResults), CAT_LIMIT) + }) ) .filter(category => category.categoryResults.length > 0) .map(({ category, categoryResults }, i) => { @@ -331,7 +336,7 @@ export function Omnibox(props: OmniboxProps): ReactElement { return ( {categoryTitle} - {categoryResults.sort(sortResults).map((result, i2) => ( + {categoryResults.map((result, i2) => ( Date: Tue, 6 Jul 2021 10:15:34 +1000 Subject: [PATCH 06/11] interface: fix mediaquery watchers on safari --- pkg/interface/src/logic/state/local.tsx | 2 ++ pkg/interface/src/views/App.js | 24 ++++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/pkg/interface/src/logic/state/local.tsx b/pkg/interface/src/logic/state/local.tsx index 9b6064106..c9a97304e 100644 --- a/pkg/interface/src/logic/state/local.tsx +++ b/pkg/interface/src/logic/state/local.tsx @@ -26,6 +26,7 @@ export interface LocalState { setTutorialRef: (el: HTMLElement | null) => void; dark: boolean; mobile: boolean; + mdBreak: boolean; background: BackgroundConfig; omniboxShown: boolean; suspendedFocus?: HTMLElement; @@ -45,6 +46,7 @@ export const selectLocalState = const useLocalState = create(persist((set, get) => ({ dark: false, mobile: false, + mdBreak: false, background: undefined, theme: 'auto', hideAvatars: false, diff --git a/pkg/interface/src/views/App.js b/pkg/interface/src/views/App.js index 7c8f028af..e60542773 100644 --- a/pkg/interface/src/views/App.js +++ b/pkg/interface/src/views/App.js @@ -83,15 +83,20 @@ class App extends React.Component { bootstrapApi(); this.props.getShallowChildren(`~${window.ship}`, 'dm-inbox'); const theme = this.getTheme(); - this.themeWatcher = window.matchMedia('(prefers-color-scheme: dark)'); - this.mobileWatcher = window.matchMedia(`(max-width: ${theme.breakpoints[0]})`); - this.themeWatcher.onchange = this.updateTheme; - this.mobileWatcher.onchange = this.updateMobile; setTimeout(() => { // Something about how the store works doesn't like changing it // before the app has actually rendered, hence the timeout. + this.themeWatcher = window.matchMedia('(prefers-color-scheme: dark)'); + this.mobileWatcher = window.matchMedia(`(max-width: ${theme.breakpoints[0]})`); + this.mediumWatcher = window.matchMedia(`(max-width: ${theme.breakpoints[1]})`); + // TODO: addListener is deprecated, but safari 13 requires it + this.themeWatcher.addListener(this.updateTheme); + this.mobileWatcher.addListener(this.updateMobile); + this.mediumWatcher.addListener(this.updateMedium); + this.updateMobile(this.mobileWatcher); this.updateTheme(this.themeWatcher); + this.updateMedium(this.mediumWatcher); }, 500); this.props.getBaseHash(); this.props.getRuntimeLag(); // TODO consider polling periodically @@ -105,8 +110,9 @@ class App extends React.Component { } componentWillUnmount() { - this.themeWatcher.onchange = undefined; - this.mobileWatcher.onchange = undefined; + this.themeWatcher.removeListener(this.updateTheme); + this.mobileWatcher.removeListener(this.updateMobile); + this.mediumWatcher.removeListener(this.updateMedium); } updateTheme(e) { @@ -121,6 +127,12 @@ class App extends React.Component { }); } + updateMedium = (e) => { + this.props.set((state) => { + state.mdBreak = e.matches; + }); + } + getTheme() { const { props } = this; return ((props.dark && props?.display?.theme == 'auto') || From bc665c61487f41f24fa18d5105edc7323f8cf305 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 6 Jul 2021 10:16:58 +1000 Subject: [PATCH 07/11] LinkBlocks: fix for smaller screen sizes Fixes urbit/landscape#1026 --- .../apps/links/components/LinkBlocks.tsx | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/pkg/interface/src/views/apps/links/components/LinkBlocks.tsx b/pkg/interface/src/views/apps/links/components/LinkBlocks.tsx index 755168967..a378298bf 100644 --- a/pkg/interface/src/views/apps/links/components/LinkBlocks.tsx +++ b/pkg/interface/src/views/apps/links/components/LinkBlocks.tsx @@ -32,7 +32,7 @@ export function LinkBlocks(props: LinkBlocksProps) { const [linkSize, setLinkSize] = useState(250); const linkSizePx = `${linkSize}px`; - const isMobile = useLocalState(s => s.mobile); + const isMobile = useLocalState(s => s.mobile || s.mdBreak); const colCount = useMemo(() => (isMobile ? 2 : 4), [isMobile]); const bind = useResize( useCallback( @@ -46,12 +46,13 @@ export function LinkBlocks(props: LinkBlocksProps) { ); useEffect(() => { - const unreads = useHarkState.getState() - .unreads.graph?.[association.resource]?.['/']?.unreads || new Set(); - Array.from((unreads as Set)).forEach((u) => { + const unreads = + useHarkState.getState().unreads.graph?.[association.resource]?.['/'] + ?.unreads || new Set(); + Array.from(unreads as Set).forEach((u) => { airlock.poke(markEachAsRead(association.resource, '/', u)); }); -}, [association.resource]); + }, [association.resource]); const orm = useMemo(() => { const nodes = [null, ...Array.from(props.graph)]; @@ -62,12 +63,12 @@ export function LinkBlocks(props: LinkBlocksProps) { return [bigInt(i), chunk]; }) ); - }, [props.graph]); + }, [props.graph, colCount]); const renderItem = useCallback( React.forwardRef(({ index }, ref) => { - const chunk = orm.get(index); - const space = [3,4]; + const chunk = orm.get(index) ?? []; + const space = [3, 3, 4]; return ( { if (!block) { return ( - + ); } const [i, node] = block; @@ -115,7 +113,13 @@ export function LinkBlocks(props: LinkBlocksProps) { ); return ( - + Date: Tue, 6 Jul 2021 10:28:12 +1000 Subject: [PATCH 08/11] tokenizeMessage: accept numbers in group names Fixes urbit/landscape#1027 --- pkg/interface/src/logic/lib/tokenizeMessage.js | 6 +++--- pkg/interface/src/logic/lib/tokenizeMessage.test.js | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/pkg/interface/src/logic/lib/tokenizeMessage.js b/pkg/interface/src/logic/lib/tokenizeMessage.js index 6071d5843..19f231316 100644 --- a/pkg/interface/src/logic/lib/tokenizeMessage.js +++ b/pkg/interface/src/logic/lib/tokenizeMessage.js @@ -5,7 +5,7 @@ const URL_REGEX = new RegExp(String(/^([^[\]]*?)(([\w\-\+]+:\/\/)[-a-zA-Z0-9:@;? const PATP_REGEX = /^([\s\S]*?)(~[a-z_-]+)([\s\S]*)/; -const GROUP_REGEX = new RegExp(String(/^([\s\S ]*?)(~[-a-z_]+\/[-a-z]+)([\s\S]*)/.source)); +const GROUP_REGEX = new RegExp(String(/^([\s\S ]*?)(~[-a-z_]+\/[-a-z0-9]+)([\s\S]*)/.source)); const convertToGroupRef = group => `web+urbitgraph://group/${group}`; @@ -33,9 +33,9 @@ const raceRegexes = (str) => { content = { url: link[2] }; } } - let perma = parsePermalink(convertToGroupRef(groupRef?.[2])); + const perma = parsePermalink(convertToGroupRef(groupRef?.[2])); const [,,host] = perma?.group.split('/') ?? []; - if(groupRef && groupRef[1].length < pfix?.length && !!perma && urbitOb.isValidPatp(host)) { + if(groupRef && groupRef[1].length < pfix?.length && Boolean(perma) && urbitOb.isValidPatp(host)) { pfix = groupRef[1]; content = permalinkToReference(perma); sfix = groupRef[3]; diff --git a/pkg/interface/src/logic/lib/tokenizeMessage.test.js b/pkg/interface/src/logic/lib/tokenizeMessage.test.js index 9958e93e2..e65f139d1 100644 --- a/pkg/interface/src/logic/lib/tokenizeMessage.test.js +++ b/pkg/interface/src/logic/lib/tokenizeMessage.test.js @@ -118,5 +118,14 @@ describe('tokenizeMessage', () => { const example = 'test ~zoid/fakegroup'; const [{ text }, ...rest] = tokenizeMessage(example); expect(text).toBe(example); + expect(rest.length).toBe(0); + }); + it('should handle groups with numbers', () => { + const example = 'oh no, ~sampel/group-123-abc'; + + const [{ text }, { reference }] = tokenizeMessage(example); + expect(text).toBe('oh no, '); + expect(reference.group).toBe('/ship/~sampel/group-123-abc'); }); }); + From d0d274cb473f28c2ffbd8ac9b66880481bebe634 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 6 Jul 2021 10:35:25 +1000 Subject: [PATCH 09/11] Omnibox: fix tsc --- .../src/logic/lib/{omnibox.js => omnibox.ts} | 18 ++++++++++++++---- .../src/views/components/leap/Omnibox.tsx | 8 ++++---- 2 files changed, 18 insertions(+), 8 deletions(-) rename pkg/interface/src/logic/lib/{omnibox.js => omnibox.ts} (92%) diff --git a/pkg/interface/src/logic/lib/omnibox.js b/pkg/interface/src/logic/lib/omnibox.ts similarity index 92% rename from pkg/interface/src/logic/lib/omnibox.js rename to pkg/interface/src/logic/lib/omnibox.ts index 1870db33f..e20fd22a7 100644 --- a/pkg/interface/src/logic/lib/omnibox.js +++ b/pkg/interface/src/logic/lib/omnibox.ts @@ -10,8 +10,18 @@ const makeIndexes = () => new Map([ ['other', []] ]); +export interface OmniboxItem { + title: string; + link: string; + app: string; + host: string; + description: string; + shiftLink: string; + shiftDescription: string; +} + // result schematic -const result = function(title, link, app, host, description = 'Open', shiftLink = null, shiftDescription = null) { +const result = function(title: string, link: string, app: string, host: string, description = 'Open', shiftLink = null as string | null, shiftDescription = null as string | null): OmniboxItem { return { 'title': title, 'link': link, @@ -93,7 +103,7 @@ const otherIndex = function(config) { return other; }; -export default function index(contacts, associations, apps, currentGroup, groups, hide) { +export default function index(contacts, associations, apps, currentGroup, groups, hide): Map { const indexes = makeIndexes(); indexes.set('ships', shipIndex(contacts)); // all metadata from all apps is indexed @@ -117,7 +127,7 @@ export default function index(contacts, associations, apps, currentGroup, groups let app = each['app-name']; if (each['app-name'] === 'contacts') { app = 'groups'; - }; + } if (each['app-name'] === 'graph') { app = each.metadata.config.graph; @@ -159,4 +169,4 @@ export default function index(contacts, associations, apps, currentGroup, groups indexes.set('other', otherIndex(hide)); return indexes; -}; +} diff --git a/pkg/interface/src/views/components/leap/Omnibox.tsx b/pkg/interface/src/views/components/leap/Omnibox.tsx index d50cbdeb0..363abcf48 100644 --- a/pkg/interface/src/views/components/leap/Omnibox.tsx +++ b/pkg/interface/src/views/components/leap/Omnibox.tsx @@ -13,7 +13,7 @@ import React, { import { useHistory, useLocation } from 'react-router-dom'; import * as ob from 'urbit-ob'; import defaultApps from '~/logic/lib/default-apps'; -import makeIndex from '~/logic/lib/omnibox'; +import makeIndex, { OmniboxItem } from '~/logic/lib/omnibox'; import { useOutsideClick } from '~/logic/lib/useOutsideClick'; import { deSig } from '~/logic/lib/util'; import useContactState from '~/logic/state/contact'; @@ -114,7 +114,7 @@ export function Omnibox(props: OmniboxProps): ReactElement { }, [props.show]); const initialResults = useMemo(() => { - return new Map( + return new Map( SEARCHED_CATEGORIES.map((category) => { if (category === 'other') { return [ @@ -132,7 +132,7 @@ export function Omnibox(props: OmniboxProps): ReactElement { return initialResults; } const q = query.toLowerCase(); - const resultsMap = new Map(); + const resultsMap = new Map(); SEARCHED_CATEGORIES.map((category) => { const categoryIndex = index.get(category); resultsMap.set( @@ -317,7 +317,7 @@ export function Omnibox(props: OmniboxProps): ReactElement { borderBottomRightRadius={2} > {SEARCHED_CATEGORIES.map(category => - Object({ + ({ category, categoryResults: _.take(results.get(category).sort(sortResults), CAT_LIMIT) }) From 85e6a7191ec550b104e9cd6626e7c90026be8618 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 6 Jul 2021 11:00:21 +1000 Subject: [PATCH 10/11] interface: do not mark DMs as loaded incorrectly --- pkg/interface/src/views/apps/chat/DmResource.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/interface/src/views/apps/chat/DmResource.tsx b/pkg/interface/src/views/apps/chat/DmResource.tsx index c3d447646..be71dfd4d 100644 --- a/pkg/interface/src/views/apps/chat/DmResource.tsx +++ b/pkg/interface/src/views/apps/chat/DmResource.tsx @@ -84,7 +84,7 @@ export function DmResource(props: DmResourceProps) { if (newer) { const index = dm.peekLargest()?.[0]; if (!index) { - return true; + return false; } await getYoungerSiblings( `~${window.ship}`, @@ -96,7 +96,7 @@ export function DmResource(props: DmResourceProps) { } else { const index = dm.peekSmallest()?.[0]; if (!index) { - return true; + return false; } await getOlderSiblings( `~${window.ship}`, From eb1994a5ffe458356a5f096eae6b41d9e58fcea8 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 6 Jul 2021 11:02:38 +1000 Subject: [PATCH 11/11] interface: fix story titles --- pkg/interface/src/stories/LinkDetail.stories.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/interface/src/stories/LinkDetail.stories.tsx b/pkg/interface/src/stories/LinkDetail.stories.tsx index d1b85274a..c2a52fe3d 100644 --- a/pkg/interface/src/stories/LinkDetail.stories.tsx +++ b/pkg/interface/src/stories/LinkDetail.stories.tsx @@ -56,7 +56,7 @@ const node = { ]) }; -const youtubeNode = { +const twitterNode = { post: { index: '/170141184504850861030994857749504231212', author: 'fabled-faster', @@ -108,7 +108,7 @@ export const Image = () => { ); }; -export const Youtube = () => { +export const Twitter = () => { const association = useMetadataState( s => s.associations.graph['/ship/~bitbet-bolbel/links'] ); @@ -116,7 +116,7 @@ export const Youtube = () => {