Merge branch 'release/next-userspace'

This commit is contained in:
Matilde Park 2020-10-01 20:40:28 -04:00
commit f76c5e13ef
27 changed files with 173 additions and 202 deletions

View File

@ -23,8 +23,10 @@
state-6
state-7
state-8
state-9
==
::
+$ state-9 [%9 state-base]
+$ state-8 [%8 state-base]
+$ state-7 [%7 state-base]
+$ state-6 [%6 state-base]
@ -56,7 +58,7 @@
$% [%chat-update update:store]
==
--
=| state-8
=| state-9
=* state -
::
%- agent:dbug
@ -85,8 +87,20 @@
=/ old !<(versioned-state old-vase)
=| cards=(list card)
|-
?: ?=(%8 -.old)
?: ?=(%9 -.old)
[cards this(state old)]
?: ?=(%8 -.old)
=/ list-paths=(list path)
%+ murn ~(tap in ~(key by synced.old))
|= =app=path
^- (unit path)
?~ (groups-of-chat:cc app-path) ~
`app-path
|-
?~ list-paths
^$(-.old %9)
=. synced.old (~(del by synced.old) i.list-paths)
$(list-paths t.list-paths)
?: ?=(%7 -.old)
=/ subscribers=(jug path ship)
%+ roll ~(val by sup.bol)
@ -104,9 +118,10 @@
|= =path
^- (unit card)
?> ?=([@ @ ~] path)
=/ group-path (group-from-chat:cc path)
=/ members (members-from-path:group group-path)
?: (is-managed-path:group group-path) ~
=/ group-paths (groups-of-chat:cc path)
?~ group-paths ~
=/ members (members-from-path:group i.group-paths)
?: (is-managed-path:group i.group-paths) ~
=/ ships=(set ship) (~(get ju subscribers) path)
%- some
=+ [%invite path (~(dif in members) ships)]

View File

@ -218,7 +218,6 @@
;~(plug (cold %ur lus) parse-url)
;~(plug (cold %ge lus) parse-model)
;~(plug (cold %te hep) sym (star ;~(pfix ace parse-source)))
;~(plug (cold %as pad) sym ;~(pfix ace parse-source))
;~(plug (cold %do cab) parse-hoon ;~(pfix ace parse-source))
parse-value
==
@ -284,6 +283,7 @@
==
++ parse-value
;~ pose
;~(plug (cold %as pad) sym ;~(pfix ace parse-source))
(stag %sa ;~(pfix tar pad sym))
(stag %ex parse-hoon)
(stag %tu (ifix [lac rac] (most ace parse-source)))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 B

View File

@ -24,6 +24,5 @@
<script src="/~landscape/js/channel.js"></script>
<script src="/~landscape/js/session.js"></script>
<script src="/~landscape/js/bundle/index.9f00eb9b1c58d2b1bd3c.js"></script>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.12.min.js"></script>
</body>
</html>

View File

@ -103,14 +103,16 @@ class Channel {
path,
connectionErrFunc = () => {},
eventFunc = () => {},
quitFunc = () => {}) {
quitFunc = () => {},
subAckFunc = () => {}) {
let id = this.nextId();
this.outstandingSubscriptions.set(
id,
{
err: connectionErrFunc,
event: eventFunc,
quit: quitFunc
quit: quitFunc,
subAck: subAckFunc
}
);
@ -205,11 +207,12 @@ class Channel {
} else if (obj.response == "subscribe" ||
(obj.response == "poke" && !!subFuncs)) {
let funcs = subFuncs;
// on a response to a subscribe, we only notify the caller on err
//
if (obj.hasOwnProperty("err")) {
funcs["err"](obj.err);
this.outstandingSubscriptions.delete(obj.id);
} else if (obj.hasOwnProperty("ok")) {
funcs["subAck"](obj);
}
} else if (obj.response == "diff") {
let funcs = subFuncs;

View File

@ -243,7 +243,10 @@
%+ rose (tufa buf.cli-state)
(command-parser:og sole-id)
?: ?=(%& -.res)
?. &(?=(^ p.res) run.u.p.res)
:: only auto-run eligible commands if they were typed out
:: (that is, not retrieved from command history)
::
?. &(?=(^ p.res) run.u.p.res !?=(%set -.ted.sole-change))
[[~ cli-state] shoe]
(run-command cmd.u.p.res)
:_ shoe

View File

@ -44,6 +44,8 @@ let devServer = {
contentBase: path.join(__dirname, '../dist'),
hot: true,
port: 9000,
host: '0.0.0.0',
disableHostCheck: true,
historyApiFallback: true
};

View File

@ -68,7 +68,7 @@ const appIndex = function (apps) {
});
// add groups separately
applications.push(
result('Groups', '/~groups', 'groups', null)
result('Groups', '/~groups', 'Groups', null)
);
return applications;
};

View File

@ -162,12 +162,9 @@ export default class ChatInput extends Component<ChatInputProps, ChatInputState>
}
if (!this.s3Uploader.current || !this.s3Uploader.current.inputRef.current) return;
this.s3Uploader.current.inputRef.current.files = files;
setTimeout(() => {
if (this.s3Uploader.current.state.isUploading) return;
const fire = document.createEvent("HTMLEvents");
fire.initEvent("change", true, true);
this.s3Uploader.current?.inputRef.current?.dispatchEvent(fire);
}, 200);
const fire = document.createEvent("HTMLEvents");
fire.initEvent("change", true, true);
this.s3Uploader.current?.inputRef.current?.dispatchEvent(fire);
}
render() {

View File

@ -30,7 +30,7 @@ export class GroupifyButton extends Component {
return this.state.targetGroup ? (
<div className="mt4">
<Toggle
boolean={inclusive}
boolean={this.state.inclusive}
change={this.changeInclusive.bind(this)}
/>
<span className="dib f9 white-d inter ml3">
@ -42,7 +42,7 @@ export class GroupifyButton extends Component {
</div>
) : <div />;
}
render() {
const { inclusive, targetGroup } = this.state;
const {
@ -52,7 +52,8 @@ export class GroupifyButton extends Component {
associations,
contacts,
groups,
station
station,
changeLoading
} = this.props;
const groupPath = association['group-path'];
@ -94,7 +95,7 @@ export class GroupifyButton extends Component {
});
}}
className={
'dib f9 black gray4-d bg-gray0-d ba pa2 mt4 b--black ' +
'dib f9 black gray4-d bg-gray0-d ba pa2 mt4 b--black ' +
'b--gray1-d pointer'
}>Convert to group</a>
</div>

View File

@ -52,7 +52,7 @@ export class NewDmScreen extends Component {
titleChange(event) {
const asciiSafe = event.target.value.toLowerCase()
.replace(/[^a-z0-9~_.-]/g, '-');
.replace(/[^a-z0-9_-]/g, '-');
this.setState({
idName: asciiSafe,
title: event.target.value

View File

@ -38,7 +38,7 @@ export class NewScreen extends Component {
titleChange(event) {
const asciiSafe = event.target.value.toLowerCase()
.replace(/[^a-z0-9~_.-]/g, '-');
.replace(/[^a-z0-9_-]/g, '-');
this.setState({
idName: asciiSafe,
title: event.target.value

View File

@ -82,6 +82,7 @@ export class SettingsScreen extends Component {
contacts={contacts}
groups={groups}
api={api}
station={station}
changeLoading={this.changeLoading} />
<DeleteButton
isOwner={isOwner}
@ -122,13 +123,6 @@ export class SettingsScreen extends Component {
location
} = this.props;
const isInPopout = popout ? "popout/" : "";
const title =
( association &&
('metadata' in association) &&
(association.metadata.title !== '')
) ? association.metadata.title : station.substr(1);
return (
<div className="h-100 w-100 overflow-x-hidden flex flex-column white-d">
<ChatHeader

View File

@ -6,10 +6,10 @@ import { Spinner } from '~/views/components/Spinner';
import { Toggle } from '~/views/components/toggle';
import { RouteComponentProps } from 'react-router-dom';
import { Groups, GroupPolicy, Resource } from '~/types/group-update';
import { Contacts, Rolodex } from '~/types/contact-update';
import { Groups, GroupPolicy } from '~/types/group-update';
import { Rolodex } from '~/types/contact-update';
import GlobalApi from '~/logic/api/global';
import { Patp, PatpNoSig, Enc } from '~/types/noun';
import { Enc } from '~/types/noun';
type NewScreenProps = Pick<RouteComponentProps, 'history'> & {
groups: Groups;
@ -20,7 +20,6 @@ type NewScreenProps = Pick<RouteComponentProps, 'history'> & {
type TextChange = React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>;
type BooleanChange = React.ChangeEvent<HTMLInputElement>;
interface NewScreenState {
groupName: string;
title: string;
@ -55,7 +54,7 @@ export class NewScreen extends Component<NewScreenProps, NewScreenState> {
groupNameChange(event: TextChange) {
const asciiSafe = event.target.value
.toLowerCase()
.replace(/[^a-z0-9~_.-]/g, '-');
.replace(/[^a-z0-9_-]/g, '-');
this.setState({
groupName: asciiSafe,
title: event.target.value,

View File

@ -98,11 +98,11 @@ export class LinkSubmit extends Component<LinkSubmitProps, LinkSubmitState> {
fetch(`https://noembed.com/embed?url=${linkValue}`)
.then(response => response.json())
.then((result) => {
if (result.title) {
if (result.title && !this.state.linkTitle) {
this.setState({ linkTitle: result.title });
}
}).catch((error) => {/*noop*/});
} else {
} else if (!this.state.linkTitle) {
this.setState({
linkTitle: decodeURIComponent(linkValue
.split('/')

View File

@ -1,13 +1,13 @@
import React, { Component, useEffect } from 'react';
import React, { useEffect } from 'react';
import { TabBar } from '~/views/components/chat-link-tabbar';
import { LinkPreview } from './lib/link-preview';
import { LinkSubmit } from './lib/link-submit';
import { CommentSubmit } from './lib/comment-submit';
import { SidebarSwitcher } from '~/views/components/SidebarSwitch';
import { Link } from 'react-router-dom';
import { Comments } from './lib/comments';
import { getContactDetails } from '~/logic/lib/util';
import { Box } from '@tlon/indigo-react';
export const LinkDetail = (props) => {
if (!props.node && props.graphResource) {
@ -29,31 +29,36 @@ export const LinkDetail = (props) => {
);
}
const { nickname } = getContactDetails(props.contacts[ship]);
const our = getContactDetails(props.contacts[window.ship]);
const { nickname } = getContactDetails(props.contacts[props.node?.post?.author]);
const resourcePath = `${props.ship}/${props.name}`;
const title = props.resource.metadata.title || resourcePath;
return (
<div className="h-100 w-100 overflow-hidden flex flex-column">
<div
className={
'pl4 pt2 flex relative overflow-x-scroll ' +
'overflow-x-auto-l overflow-x-auto-xl flex-shrink-0 ' +
'bb bn-m bn-l bn-xl b--gray4'
}
style={{ height: 48 }}>
<Box
pl='12px'
pt='2'
display='flex'
position='relative'
overflowX={['scroll', 'auto']}
flexShrink='0'
borderBottom='1px solid'
borderColor='washedGray'
height='48px'
>
<SidebarSwitcher
sidebarShown={props.sidebarShown}
popout={props.popout}
api={props.api}
/>
<Link className="dib f9 fw4 pt2 gray2 lh-solid"
to={`/~link/${resourcePath}`}>
to={`/~link/${resourcePath}`}
>
<h2
className="dib f9 fw4 lh-solid v-top black white-d"
style={{ width: 'max-content' }}>
{`<- ${title}`}
style={{ width: 'max-content' }}
>
{`${title}`}
</h2>
</Link>
<TabBar
@ -62,7 +67,7 @@ export const LinkDetail = (props) => {
popoutHref={`/~link/popout/${resourcePath}/${props.match.params.index}`}
settings={`/~link/${resourcePath}/settings`}
/>
</div>
</Box>
<div className="w-100 mt2 flex justify-center overflow-y-scroll ph4 pb4">
<div className="w-100 mw7">
<LinkPreview
@ -78,7 +83,8 @@ export const LinkDetail = (props) => {
name={props.name}
ship={props.ship}
api={props.api}
parentIndex={props.node.post.index} />
parentIndex={props.node.post.index}
/>
</div>
<Comments
comments={props.node.children}
@ -88,10 +94,11 @@ export const LinkDetail = (props) => {
api={props.api}
hideAvatars={props.hideAvatars}
hideNicknames={props.hideNicknames}
remoteContentPolicy={props.remoteContentPolicy} />
remoteContentPolicy={props.remoteContentPolicy}
/>
</div>
</div>
</div>
);
}
};

View File

@ -5,6 +5,7 @@ import { SidebarSwitcher } from '~/views/components/SidebarSwitch';
import { Link } from 'react-router-dom';
import { LinkItem } from './lib/link-item';
import LinkSubmit from './lib/link-submit';
import { Box } from '@tlon/indigo-react';
import { getContactDetails } from '~/logic/lib/util';
@ -38,12 +39,16 @@ export const LinkList = (props) => {
style={{ height: '1rem' }}>
<Link to="/~link">{'⟵ All Channels'}</Link>
</div>
<div className={
'pl4 pt2 flex relative overflow-x-scroll' +
'overflow-x-auto-l overflow-x-auto-xl flex-shrink-0' +
'bb b--gray4 b--gray1-d bg-gray0-d'
}
style={{ height: 48 }}>
<Box
pl='12px'
pt='2'
display='flex'
position='relative'
overflowX={['scroll', 'auto']}
flexShrink='0'
borderBottom='1px solid'
borderColor='washedGray'
height='48px'>
<SidebarSwitcher
sidebarShown={props.sidebarShown}
popout={props.popout}
@ -59,7 +64,7 @@ export const LinkList = (props) => {
popoutHref={`/~link/popout/${resource}`}
settings={`/~link/${resource}/settings`}
/>
</div>
</Box>
<div className="w-100 mt6 flex justify-center overflow-y-scroll ph4 pb4">
<div className="w-100 mw7">
<div className="flex">
@ -71,10 +76,10 @@ export const LinkList = (props) => {
</div>
{ Array.from(props.graph).map(([date, node]) => {
const { nickname, color, avatar } =
getContactDetails(props.contacts[ship]);
getContactDetails(props.contacts[node?.post?.author]);
return (
<LinkItem
key={date}
resource={resource}
node={node}
nickname={nickname}

View File

@ -7,6 +7,8 @@ import { Spinner } from '~/views/components/Spinner';
import { TabBar } from '~/views/components/chat-link-tabbar';
import SidebarSwitcher from '~/views/components/SidebarSwitch';
import { Box } from '@tlon/indigo-react';
import { MetadataSettings } from '~/views/components/metadata/settings';
export class SettingsScreen extends Component {
@ -132,12 +134,16 @@ export class SettingsScreen extends Component {
style={{ height: '1rem' }}>
<Link to="/~link">{'⟵ All Collections'}</Link>
</div>
<div
className={
"pl4 pt2 bb b--gray4 b--gray1-d flex relative overflow-x-scroll " +
"overflow-x-auto-l overflow-x-auto-xl flex-shrink-0"
}
style={{ height: 48 }}>
<Box
pl='12px'
pt='2'
display='flex'
position='relative'
overflowX={['scroll', 'auto']}
flexShrink='0'
borderBottom='1px solid'
borderColor='washedGray'
height='48px'>
<SidebarSwitcher
sidebarShown={this.props.sidebarShown}
popout={this.props.popout}
@ -157,7 +163,7 @@ export class SettingsScreen extends Component {
popoutHref={`/~link/popout/${props.resourcePath}/settings`}
settings={`/~link/${props.resourcePath}/settings`}
/>
</div>
</Box>
<div className="w-100 pl3 mt4 cf">
<h2 className="f8 pb2">Collection Settings</h2>
{this.renderRemove()}

View File

@ -63,6 +63,7 @@ export function MarkdownEditor(
{...boxProps}
>
<CodeEditor
autoCursor={false}
onBlur={onBlur}
value={value}
options={options}

View File

@ -128,7 +128,7 @@ export function DropdownSearch<C>(props: DropdownSearchProps<C>) {
);
return (
<Box position="relative">
<Box position="relative" zIndex={9}>
<Label htmlFor={props.id}>{props.label}</Label>
{caption ? <Label mt="2" gray>{caption}</Label> : null}
{!props.disabled && (

View File

@ -10,7 +10,6 @@ import { Sigil } from '~/logic/lib/sigil';
const StatusBar = (props) => {
const location = useLocation();
const atHome = Boolean(location.pathname === '/');
const display = (!window.location.href.includes('popout/'))
? 'grid' : 'none';
@ -33,17 +32,10 @@ const StatusBar = (props) => {
>
<Row collapse>
<StatusBarItem mr={2} onClick={() => props.history.push('/')}>
<img
className='invert-d'
src='/~landscape/img/icon-home.png'
height='11'
width='11'
/>
<Icon icon='Home' color='transparent' stroke='black' />
</StatusBarItem>
<StatusBarItem mr={2} onClick={() => props.api.local.setOmnibox()}>
<Text display='inline-block' style={{ transform: 'rotate(180deg)' }}>
</Text>
<Icon icon='LeapArrow'/>
<Text ml={2} color='black'>
Leap
</Text>
@ -54,12 +46,7 @@ const StatusBar = (props) => {
<StatusBarItem
onClick={() => props.history.push('/~groups')}
badge={Object.keys(invites).length > 0}>
<img
className='invert-d v-mid'
src='/~landscape/img/groups.png'
height='15'
width='15'
/>
<Icon icon='Groups' color='transparent' stroke='black'/>
<Text display={["none", "inline"]} ml={2}>Groups</Text>
</StatusBarItem>
<ReconnectButton

View File

@ -31,10 +31,8 @@ export function StatusBarItem({
<Icon
size="22px"
icon="Bullet"
fill="blue"
position="absolute"
top={"-10px"}
right={"-12px"}
color="blue"
style={{ position: 'absolute', top: '-10', right: '-11' }}
/>
)}
</Row>

View File

@ -26,43 +26,22 @@ export class OmniboxResult extends Component {
}
getIcon(icon, dark, selected, link) {
// graphicStyle is only necessary for pngs
//
//TODO can be removed after indigo-react 1.2
//which includes icons for apps
let graphicStyle = {};
if (icon.toLowerCase() !== 'dojo') {
graphicStyle = (!dark && this.state.hovered) ||
selected === link ||
(dark && !(this.state.hovered || selected === link))
? { filter: 'invert(1)' }
: { filter: 'invert(0)' };
} else {
graphicStyle =
(!dark && this.state.hovered) ||
selected === link ||
(dark && !(this.state.hovered || selected === link))
? { filter: 'invert(0)' }
: { filter: 'invert(1)' };
}
const iconFill = this.state.hovered || selected === link ? 'white' : 'black';
const sigilFill = this.state.hovered || selected === link ? '#3a8ff7' : '#ffffff';
const iconFill = (this.state.hovered || (selected === link)) ? 'white' : 'black';
const sigilFill = (this.state.hovered || (selected === link)) ? '#3a8ff7' : '#ffffff';
let graphic = <div />;
if (defaultApps.includes(icon.toLowerCase()) || icon.toLowerCase() === 'links') {
graphic =
<img className="mr2 v-mid dib" height="16"
width="16" src={`/~landscape/img/${icon.toLowerCase()}.png`}
style={graphicStyle}
/>;
icon = (icon === 'Dojo') ? 'ChevronEast' : icon;
icon = (icon === 'Link') ? 'Links' : icon;
const color = (icon === 'ChevronEast') ? iconFill : 'transparent';
const stroke = (icon === 'ChevronEast') ? 'transparent' : iconFill;
graphic = <Icon display="inline-block" verticalAlign="middle" icon={icon} mr='2' size='16px' color={color} stroke={stroke} />;
} else if (icon === 'logout') {
graphic = <Icon display="inline-block" verticalAlign="middle" icon='ArrowWest' mr='2' size='16px' fill={iconFill} />;
graphic = <Icon display="inline-block" verticalAlign="middle" icon='ArrowWest' mr='2' size='16px' color={iconFill} />;
} else if (icon === 'profile') {
graphic = <Sigil color={sigilFill} classes='dib v-mid mr2' ship={window.ship} size={16} />;
} else {
graphic = <Icon verticalAlign="middle" mr='2' size="16px" fill={iconFill} />;
graphic = <Icon verticalAlign="middle" mr='2' size="16px" color={iconFill} />;
}
return graphic;
@ -78,68 +57,40 @@ export class OmniboxResult extends Component {
const graphic = this.getIcon(icon, dark, selected, link);
return (
<Row
py='2'
px='2'
display='flex'
flexDirection='row'
style={{ cursor: 'pointer' }}
onMouseEnter={() => this.setHover(true)}
onMouseLeave={() => this.setHover(false)}
backgroundColor={
this.state.hovered || selected === link ? 'blue' : 'white'
}
onClick={navigate}
width="100%"
ref={this.result}
<Row
py='2'
px='2'
cursor='pointer'
onMouseEnter={() => this.setHover(true)}
onMouseLeave={() => this.setHover(false)}
backgroundColor={
this.state.hovered || selected === link ? 'blue' : 'white'
}
onClick={navigate}
width="100%"
ref={this.result}
>
{graphic}
<Text
display="inline-block"
verticalAlign="middle"
color={this.state.hovered || selected === link ? 'white' : 'black'}
maxWidth="60%"
style={{ flexShrink: 0 }}
mr='1'
>
{this.state.hovered || selected === link ? (
<>
{graphic}
<Text
display="inline-block"
verticalAlign="middle"
color='white'
maxWidth="60%"
style={{ flexShrink: 0 }}
mr='1'>
{text}
</Text>
<Text pr='2'
display="inline-block"
verticalAlign="middle"
color='white'
width='100%'
textAlign='right'
>
{subtext}
</Text>
</>
) : (
<>
{graphic}
<Text
mr='1'
display="inline-block"
verticalAlign="middle"
maxWidth="60%"
style={{ flexShrink: 0 }}
>
{text}
</Text>
<Text
pr='2'
display="inline-block"
verticalAlign="middle"
gray
width='100%'
textAlign='right'
>
{subtext}
</Text>
</>
)}
</Row>
{text}
</Text>
<Text pr='2'
display="inline-block"
verticalAlign="middle"
color={this.state.hovered || selected === link ? 'white' : 'black'}
width='100%'
textAlign='right'
>
{subtext}
</Text>
</Row>
);
}
}

View File

@ -42,8 +42,8 @@ export const MetadataSettings = (props) => {
val,
association.metadata.description,
association.metadata['date-created'],
module,
uxToHex(association.metadata.color)
uxToHex(association.metadata.color),
module
).then(() => {
changeLoading(false, false, '', () => {});
});

View File

@ -99,22 +99,25 @@ export class S3Upload extends Component<S3UploadProps, S3UploadState> {
const timestamp = deSig(dateToDa(new Date()));
let bucket = props.configuration.currentBucket;
this.setState({ isUploading: true });
setTimeout(() => {
if (this.state.isUploading) return;
this.setState({ isUploading: true });
this.s3.upload(bucket, `${window.ship}/${timestamp}-${fileName}.${fileExtension}`, file)
.then((data) => {
if (!data || !('Location' in data)) {
return;
}
this.props.uploadSuccess(data.Location);
})
.catch((err) => {
console.error(err);
this.props.uploadError(err);
})
.finally(() => {
this.setState({ isUploading: false });
});
}, 200);
this.s3.upload(bucket, `${window.ship}/${timestamp}-${fileName}.${fileExtension}`, file)
.then((data) => {
if (!data || !('Location' in data)) {
return;
}
this.props.uploadSuccess(data.Location);
})
.catch((err) => {
console.error(err);
this.props.uploadError(err);
})
.finally(() => {
this.setState({ isUploading: false });
});
}
onClick() {