mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-15 01:52:42 +03:00
interface: working sidebar and new page
This commit is contained in:
parent
0f2c4d069e
commit
7ef30187bb
@ -9,7 +9,6 @@ export default class BaseApi<S extends object = {}> {
|
||||
|
||||
unsubscribe(id: number) {
|
||||
this.channel.unsubscribe(id);
|
||||
|
||||
}
|
||||
|
||||
subscribe(path: Path, method, ship = this.ship, app: string, success, fail, quit) {
|
||||
@ -37,19 +36,20 @@ export default class BaseApi<S extends object = {}> {
|
||||
);
|
||||
}
|
||||
|
||||
action(appl: string, mark: string, data: any): Promise<any> {
|
||||
action(
|
||||
appl: string,
|
||||
mark: string,
|
||||
data: any,
|
||||
ship = (window as any).ship
|
||||
): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.channel.poke(
|
||||
(window as any).ship,
|
||||
ship,
|
||||
appl,
|
||||
mark,
|
||||
data,
|
||||
(json) => {
|
||||
resolve(json);
|
||||
},
|
||||
(err) => {
|
||||
reject(err);
|
||||
}
|
||||
(json) => { resolve(json); },
|
||||
(err) => { reject(err); }
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -58,9 +58,7 @@ export default class BaseApi<S extends object = {}> {
|
||||
return fetch(`/~/scry/${app}${path}.json`).then(r => r.json() as Promise<T>);
|
||||
}
|
||||
|
||||
|
||||
async spider<T>(inputMark: string, outputMark: string, threadName: string, body: any): Promise<T> {
|
||||
|
||||
const res = await fetch(`/spider/${inputMark}/${threadName}/${outputMark}.json`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body)
|
||||
|
@ -4,6 +4,7 @@ import { Patp, Path, PatpNoSig } from '~/types/noun';
|
||||
import _ from 'lodash';
|
||||
import {makeResource, resourceFromPath} from '../lib/group';
|
||||
import {GroupPolicy, Enc, Post} from '~/types';
|
||||
import { deSig } from '~/logic/lib/util';
|
||||
|
||||
export const createPost = (contents: Object[], parentIndex: string = '') => {
|
||||
return {
|
||||
@ -26,10 +27,19 @@ export default class GraphApi extends BaseApi<StoreState> {
|
||||
return this.spider('graph-view-action', 'json', threadName, action);
|
||||
}
|
||||
|
||||
createManagedGraph(name: string, title: string, description: string, group: Path) {
|
||||
const associated = { group: resourceFromPath(group) };
|
||||
private hookAction(ship: Patp, action: any): Promise<any> {
|
||||
return this.action('graph-push-hook', 'graph-update', action, deSig(ship));
|
||||
}
|
||||
|
||||
createManagedGraph(
|
||||
name: string,
|
||||
title: string,
|
||||
description: string,
|
||||
group: Path
|
||||
) {
|
||||
const associated = { group: resourceFromPath(group) };
|
||||
const resource = makeResource(`~${window.ship}`, name);
|
||||
|
||||
return this.viewAction('graph-create', {
|
||||
"create": {
|
||||
resource,
|
||||
@ -40,9 +50,14 @@ export default class GraphApi extends BaseApi<StoreState> {
|
||||
});
|
||||
}
|
||||
|
||||
createUnmanagedGraph(name: string, title: string, description: string, policy: Enc<GroupPolicy>) {
|
||||
|
||||
createUnmanagedGraph(
|
||||
name: string,
|
||||
title: string,
|
||||
description: string,
|
||||
policy: Enc<GroupPolicy>
|
||||
) {
|
||||
const resource = makeResource(`~${window.ship}`, name);
|
||||
|
||||
return this.viewAction('graph-create', {
|
||||
"create": {
|
||||
resource,
|
||||
@ -85,7 +100,7 @@ export default class GraphApi extends BaseApi<StoreState> {
|
||||
}
|
||||
|
||||
addGraph(ship: Patp, name: string, graph: any, mark: any) {
|
||||
this.storeAction({
|
||||
return this.storeAction({
|
||||
'add-graph': {
|
||||
resource: { ship, name },
|
||||
graph,
|
||||
@ -95,7 +110,7 @@ export default class GraphApi extends BaseApi<StoreState> {
|
||||
}
|
||||
|
||||
removeGraph(ship: Patp, name: string) {
|
||||
this.storeAction({
|
||||
return this.storeAction({
|
||||
'remove-graph': {
|
||||
resource: { ship, name }
|
||||
}
|
||||
@ -110,7 +125,7 @@ export default class GraphApi extends BaseApi<StoreState> {
|
||||
children: { empty: null }
|
||||
};
|
||||
|
||||
return this.storeAction({
|
||||
return this.hookAction(ship, {
|
||||
'add-nodes': {
|
||||
resource,
|
||||
nodes
|
||||
@ -119,7 +134,7 @@ export default class GraphApi extends BaseApi<StoreState> {
|
||||
}
|
||||
|
||||
addNodes(ship: Patp, name: string, nodes: Object) {
|
||||
this.storeAction({
|
||||
this.hookAction(ship, {
|
||||
'add-nodes': {
|
||||
resource: { ship, name },
|
||||
nodes
|
||||
@ -128,7 +143,7 @@ export default class GraphApi extends BaseApi<StoreState> {
|
||||
}
|
||||
|
||||
removeNodes(ship: Patp, name: string, indices: string[]) {
|
||||
return this.storeAction({
|
||||
return this.hookAction(ship, {
|
||||
'remove-nodes': {
|
||||
resource: { ship, name },
|
||||
indices
|
||||
|
@ -83,6 +83,9 @@ export class LinksApp extends Component {
|
||||
graphKeys={graphKeys}>
|
||||
<NewScreen
|
||||
api={api}
|
||||
graphKeys={graphKeys}
|
||||
associations={associations}
|
||||
groups={groups}
|
||||
{...props}
|
||||
/>
|
||||
</Skeleton>
|
||||
@ -200,8 +203,6 @@ export class LinksApp extends Component {
|
||||
const popout = props.match.url.includes('/popout/');
|
||||
const contactDetails = contacts[resource['group-path']] || {};
|
||||
|
||||
console.log(props.match.params.index.split('-'));
|
||||
|
||||
const indexArr = props.match.params.index.split('-');
|
||||
const graph = graphs[resourcePath] || null;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { makeRoutePath } from '~/logic/lib/util';
|
||||
|
||||
|
||||
export class ChannelItem extends Component {
|
||||
render() {
|
||||
@ -15,7 +15,7 @@ export class ChannelItem extends Component {
|
||||
: null;
|
||||
|
||||
return (
|
||||
<Link to={makeRoutePath(props.link)}>
|
||||
<Link to={`/~link/${props.link}`}>
|
||||
<div className={'w-100 v-mid f9 ph5 z1 pv1 relative ' + selectedClass}>
|
||||
<p className="f9 dib">{props.name}</p>
|
||||
<p className="f9 dib fr">
|
||||
|
@ -22,12 +22,16 @@ export const ChannelSidebar = (props) => {
|
||||
const associations = props.associations.contacts ?
|
||||
alphabetiseAssociations(props.associations.contacts) : {};
|
||||
|
||||
const graphAssoc = props.associations.graph || {};
|
||||
|
||||
const groupedChannels = {};
|
||||
[...props.graphKeys].map((path) => {
|
||||
const groupPath = props.associations.link[path] ?
|
||||
props.associations.link[path]['group-path'] : '';
|
||||
[...props.graphKeys].map((gKey) => {
|
||||
const path = `/ship/~${gKey.split('/')[0]}/${gKey.split('/')[1]}`;
|
||||
const groupPath = graphAssoc[path] ? graphAssoc[path]['group-path'] : '';
|
||||
|
||||
if (groupPath in associations) {
|
||||
// managed
|
||||
|
||||
if (groupedChannels[groupPath]) {
|
||||
const array = groupedChannels[groupPath];
|
||||
array.push(path);
|
||||
@ -35,51 +39,51 @@ export const ChannelSidebar = (props) => {
|
||||
} else {
|
||||
groupedChannels[groupPath] = [path];
|
||||
}
|
||||
|
||||
} else {
|
||||
// unmanaged
|
||||
|
||||
if (groupedChannels['/~/']) {
|
||||
const array = groupedChannels['/~/'];
|
||||
array.push(path);
|
||||
groupedChannels['/~/'] = array;
|
||||
} else {
|
||||
groupedChannels['/~/'] = [path];
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let i = -1;
|
||||
//TODO handle unmanaged links
|
||||
const groupedItems = Object.keys(associations).map((each, i) => {
|
||||
const channels = groupedChannels[each];
|
||||
if (!channels || channels.length === 0) { return; }
|
||||
|
||||
const groupedItems = Object.keys(associations)
|
||||
.map((each) => {
|
||||
const channels = groupedChannels[each];
|
||||
if (!channels || channels.length === 0)
|
||||
return;
|
||||
i++;
|
||||
if (groupedChannels['/~/'] && groupedChannels['/~/'].length !== 0) {
|
||||
i++;
|
||||
}
|
||||
return (
|
||||
<GroupItem
|
||||
key={i + 1}
|
||||
unmanaged={false}
|
||||
association={associations[each]}
|
||||
metadata={graphAssoc}
|
||||
channels={channels}
|
||||
selected={props.selected}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<GroupItem
|
||||
key={i}
|
||||
index={i}
|
||||
association={associations[each]}
|
||||
linkMetadata={props.associations['link']}
|
||||
channels={channels}
|
||||
selected={props.selected}
|
||||
/>
|
||||
);
|
||||
});
|
||||
if (groupedChannels['/~/'] && groupedChannels['/~/'].length !== 0) {
|
||||
groupedItems.push(
|
||||
<GroupItem
|
||||
key={0}
|
||||
unmanaged={true}
|
||||
association={'/~/'}
|
||||
metadata={graphAssoc}
|
||||
channels={groupedChannels['/~/']}
|
||||
selected={props.selected}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const activeClasses = (props.active === 'collections') ? ' ' : 'dn-s ';
|
||||
|
||||
let hiddenClasses = true;
|
||||
|
||||
if (props.popout) {
|
||||
hiddenClasses = false;
|
||||
} else {
|
||||
hiddenClasses = props.sidebarShown;
|
||||
}
|
||||
const hiddenClasses = !!props.popout ? false : props.sidebarShown;
|
||||
|
||||
return (
|
||||
<div className={
|
||||
|
@ -36,8 +36,8 @@ export const CommentItem = (props) => {
|
||||
{content}
|
||||
</RichText>
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
</Row>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import { ChannelItem } from './channel-item';
|
||||
import { deSig } from '~/logic/lib/util';
|
||||
|
||||
|
||||
export const GroupItem = (props) => {
|
||||
const association = props.association ? props.association : {};
|
||||
@ -13,16 +15,18 @@ export const GroupItem = (props) => {
|
||||
}
|
||||
|
||||
const channels = props.channels ? props.channels : [];
|
||||
const first = (props.index === 0) ? 'pt1' : 'pt6';
|
||||
const unmanaged = props.unmanaged ? 'pt6' : 'pt1';
|
||||
|
||||
const channelItems = channels.map((each, i) => {
|
||||
const meta = props.linkMetadata[each];
|
||||
const meta = props.metadata[each];
|
||||
if (!meta) { return null; }
|
||||
const link = `${deSig(each.split('/')[2])}/${each.split('/')[3]}`;
|
||||
|
||||
const selected = (props.selected === each);
|
||||
return (
|
||||
<ChannelsItem
|
||||
<ChannelItem
|
||||
key={each}
|
||||
link={each}
|
||||
link={link}
|
||||
selected={selected}
|
||||
name={meta.metadata.title}
|
||||
/>
|
||||
@ -30,7 +34,7 @@ export const GroupItem = (props) => {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={first}>
|
||||
<div className={unmanaged}>
|
||||
<p className="f9 ph4 pb2 gray3">{title}</p>
|
||||
{channelItems}
|
||||
</div>
|
||||
|
@ -10,7 +10,6 @@ import { getContactDetails } from '~/logic/lib/util';
|
||||
|
||||
|
||||
export const LinkDetail = (props) => {
|
||||
console.log(props);
|
||||
if (!props.node) {
|
||||
// TODO: something
|
||||
return (
|
||||
|
@ -1,41 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import urbitOb from 'urbit-ob';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { InviteSearch } from '~/views/components/InviteSearch';
|
||||
import { Spinner } from '~/views/components/Spinner';
|
||||
import { makeRoutePath, deSig } from '~/logic/lib/util';
|
||||
|
||||
export const NewScreen = (props) => {
|
||||
const onClickCreate = () => {
|
||||
|
||||
let name = 'a' + String(Math.floor(Math.random() * 100));
|
||||
let res = `/~tacryt-socryp/` + name;
|
||||
props.api.metadata.metadataAdd(
|
||||
'link',
|
||||
res,
|
||||
'/~tacryt-socryp/aaa',
|
||||
name,
|
||||
'',
|
||||
'~2000.1.1',
|
||||
'000000'
|
||||
);
|
||||
|
||||
props.api.graph.addGraph(
|
||||
`~${window.ship}`,
|
||||
name,
|
||||
{},
|
||||
null
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button
|
||||
onClick={onClickCreate}>
|
||||
Start Chat
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
107
pkg/interface/src/views/apps/links/components/new.tsx
Normal file
107
pkg/interface/src/views/apps/links/components/new.tsx
Normal file
@ -0,0 +1,107 @@
|
||||
import React, { useCallback } from "react";
|
||||
import { RouteComponentProps } from "react-router-dom";
|
||||
import { Box, Input, Col } from "@tlon/indigo-react";
|
||||
import { Formik, Form } from "formik";
|
||||
import * as Yup from "yup";
|
||||
|
||||
import { AsyncButton } from "~/views/components/AsyncButton";
|
||||
import { FormError } from "~/views/components/FormError";
|
||||
import GroupSearch from "~/views/components/GroupSearch";
|
||||
|
||||
import GlobalApi from "~/logic/api/global";
|
||||
import { stringToSymbol } from "~/logic/lib/util";
|
||||
import { useWaitForProps } from "~/logic/lib/useWaitForProps";
|
||||
|
||||
import { Associations } from "~/types/metadata-update";
|
||||
import { Notebooks } from "~/types/publish-update";
|
||||
import { Groups, GroupPolicy } from "~/types/group-update";
|
||||
|
||||
const formSchema = Yup.object({
|
||||
name: Yup.string().required("Collection must have a name"),
|
||||
description: Yup.string(),
|
||||
group: Yup.string(),
|
||||
});
|
||||
|
||||
|
||||
export function NewScreen(props: object) {
|
||||
const { history, api } = props;
|
||||
const waiter = useWaitForProps(props, 5000);
|
||||
|
||||
const onSubmit = async (values: object, actions) => {
|
||||
const resourceId = stringToSymbol(values.name);
|
||||
try {
|
||||
const { name, description, group } = values;
|
||||
if (!!group) {
|
||||
await props.api.graph.createManagedGraph(
|
||||
resourceId,
|
||||
name,
|
||||
description,
|
||||
group
|
||||
);
|
||||
} else {
|
||||
await props.api.graph.createUnmanagedGraph(
|
||||
resourceId,
|
||||
name,
|
||||
description,
|
||||
{ open: {
|
||||
banRanks: [],
|
||||
banned: [],
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
await waiter((p) => p?.graphKeys?.has(`${window.ship}/${resourceId}`));
|
||||
actions.setStatus({ success: null });
|
||||
history.push(`/~link/${window.ship}/${resourceId}`);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
actions.setStatus({ error: "Collection creation failed" });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Col p={3}>
|
||||
<Box mb={4} color="black">New Collection</Box>
|
||||
<Formik
|
||||
validationSchema={formSchema}
|
||||
initialValues={{ name: "", description: "", group: "" }}
|
||||
onSubmit={onSubmit}>
|
||||
<Form>
|
||||
<Box
|
||||
display="grid"
|
||||
gridTemplateRows="auto"
|
||||
gridRowGap={2}
|
||||
gridTemplateColumns="300px">
|
||||
<Input
|
||||
id="name"
|
||||
label="Name"
|
||||
caption="Provide a name for your collection"
|
||||
placeholder="eg. My Links"
|
||||
/>
|
||||
<Input
|
||||
id="description"
|
||||
label="Description"
|
||||
caption="What's your collection about?"
|
||||
placeholder="Collection description"
|
||||
/>
|
||||
<GroupSearch
|
||||
id="group"
|
||||
label="Group"
|
||||
caption="What group is the collection for?"
|
||||
associations={props.associations}
|
||||
/>
|
||||
<Box justifySelf="start">
|
||||
<AsyncButton loadingText="Creating..." type="submit" border>
|
||||
Create Collection
|
||||
</AsyncButton>
|
||||
</Box>
|
||||
<FormError message="Collection creation failed" />
|
||||
</Box>
|
||||
</Form>
|
||||
</Formik>
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
|
||||
export default NewScreen;
|
Loading…
Reference in New Issue
Block a user