link: rewrite metadata structure for consistency

This commit is contained in:
Matilde Park 2020-03-05 20:26:03 -05:00
parent 12cae5dda8
commit 7ec75dcd62
11 changed files with 94 additions and 90 deletions

View File

@ -21,8 +21,8 @@ export class ChannelsSidebar extends Component {
}); });
const channelItems = const channelItems =
Object.keys(props.resources).map((path) => { Object.keys(props.associations).map((path) => {
const meta = props.resources[path]; const meta = props.associations[path];
const selected = (props.selected === path); const selected = (props.selected === path);
const linkCount = !!props.links[path] ? props.links[path].totalItems : 0; const linkCount = !!props.links[path] ? props.links[path].totalItems : 0;
const unseenCount = !!props.links[path] const unseenCount = !!props.links[path]
@ -37,7 +37,7 @@ export class ChannelsSidebar extends Component {
selected={selected} selected={selected}
linkCount={linkCount} linkCount={linkCount}
unseenCount={unseenCount} unseenCount={unseenCount}
name={meta.title}/> name={meta.metadata.title}/>
); );
}); });
@ -61,7 +61,7 @@ export class ChannelsSidebar extends Component {
: "dn")}> : "dn")}>
<a className="db dn-m dn-l dn-xl f8 pb3 pl3" href="/"> Landscape</a> <a className="db dn-m dn-l dn-xl f8 pb3 pl3" href="/"> Landscape</a>
<div className="overflow-y-scroll h-100"> <div className="overflow-y-scroll h-100">
<div className="w-100 bg-transparent pa4 bb b--gray4 b--gray1-d" <div className="w-100 bg-transparent pa4 bb b--gray4 b--gray2-d"
style={{paddingBottom: 10, paddingTop: 10}}> style={{paddingBottom: 10, paddingTop: 10}}>
<Link <Link
className="dib f9 pointer green2 gray4-d mr4" className="dib f9 pointer green2 gray4-d mr4"

View File

@ -104,7 +104,7 @@ export class LinkDetail extends Component {
<Link <Link
className="dib f9 fw4 pt2 gray2 lh-solid" className="dib f9 fw4 pt2 gray2 lh-solid"
to={makeRoutePath(props.resourcePath, props.popout, props.page)}> to={makeRoutePath(props.resourcePath, props.popout, props.page)}>
{`<- ${props.resource.title} index`} {`<- ${props.resource.metadata.title}`}
</Link> </Link>
<LinksTabBar {...props} popout={props.popout} resourcePath={props.resourcePath} /> <LinksTabBar {...props} popout={props.popout} resourcePath={props.resourcePath} />
</div> </div>

View File

@ -37,7 +37,7 @@ export class Links extends Component {
render() { render() {
let props = this.props; let props = this.props;
if (!props.resource.title) { if (!props.resource.metadata.title) {
return <LoadingScreen/>; return <LoadingScreen/>;
} }
@ -106,7 +106,7 @@ export class Links extends Component {
popout={props.popout}/> popout={props.popout}/>
<Link to={makeRoutePath(props.resourcePath, props.popout, props.page)} className="pt2"> <Link to={makeRoutePath(props.resourcePath, props.popout, props.page)} className="pt2">
<h2 className={`dib f9 fw4 v-top`}> <h2 className={`dib f9 fw4 v-top`}>
{props.resource.title} {props.resource.metadata.title}
</h2> </h2>
</Link> </Link>
<LinksTabBar <LinksTabBar

View File

@ -58,7 +58,7 @@ export class MemberScreen extends Component {
<h2 <h2
className="dib f9 fw4 v-top" className="dib f9 fw4 v-top"
style={{ width: "max-content" }}> style={{ width: "max-content" }}>
{props.resource.title} {props.resource.metadata.title}
</h2> </h2>
</Link> </Link>
<LinksTabBar <LinksTabBar

View File

@ -30,7 +30,7 @@ export class NewScreen extends Component {
if (prevProps !== props) { if (prevProps !== props) {
let target = `/${state.idName}`; let target = `/${state.idName}`;
if (target in props.resources) { if (target in props.associations) {
props.history.push(makeRoutePath(target)); props.history.push(makeRoutePath(target));
} }
} }
@ -77,7 +77,7 @@ export class NewScreen extends Component {
let appPath = `/${state.idName}`; let appPath = `/${state.idName}`;
if (appPath in props.resources) { if (appPath in props.associations) {
this.setState({ this.setState({
inviteError: false, inviteError: false,
idError: true, idError: true,

View File

@ -33,7 +33,7 @@ export class Root extends Component {
let contacts = !!state.contacts ? state.contacts : {}; let contacts = !!state.contacts ? state.contacts : {};
const groups = !!state.groups ? state.groups : {}; const groups = !!state.groups ? state.groups : {};
const resources = !!state.resources ? state.resources : {}; const associations = !!state.associations ? state.associations : {link: {}, contacts: {}};
let links = !!state.links ? state.links : {}; let links = !!state.links ? state.links : {};
let comments = !!state.comments ? state.comments : {}; let comments = !!state.comments ? state.comments : {};
const seen = !!state.seen ? state.seen : {}; const seen = !!state.seen ? state.seen : {};
@ -49,7 +49,7 @@ export class Root extends Component {
<Skeleton <Skeleton
active="collections" active="collections"
spinner={state.spinner} spinner={state.spinner}
resources={resources} associations={associations.link}
invites={invites} invites={invites}
groups={groups} groups={groups}
rightPanelHide={true} rightPanelHide={true}
@ -70,14 +70,14 @@ export class Root extends Component {
return ( return (
<Skeleton <Skeleton
spinner={state.spinner} spinner={state.spinner}
resources={resources} associations={associations.link}
invites={invites} invites={invites}
groups={groups} groups={groups}
rightPanelHide={true} rightPanelHide={true}
sidebarShown={state.sidebarShown} sidebarShown={state.sidebarShown}
links={links}> links={links}>
<NewScreen <NewScreen
resources={resources} associations={associations}
groups={groups} groups={groups}
contacts={contacts} contacts={contacts}
{...props} {...props}
@ -96,16 +96,16 @@ export class Root extends Component {
render={(props) => { render={(props) => {
const popout = props.match.url.includes("/popout/"); const popout = props.match.url.includes("/popout/");
const resourcePath = '/' + props.match.params.resource; const resourcePath = '/' + props.match.params.resource;
const resource = resources[resourcePath] || {}; const resource = associations.link[resourcePath] || {metadata: {}};
const contactDetails = contacts[resource.group] || {}; const contactDetails = contacts[resource["group-path"]] || {};
const group = groups[resource.group] || new Set([]); const group = groups[resource["group-path"]] || new Set([]);
const amOwner = amOwnerOfGroup(resource.group); const amOwner = amOwnerOfGroup(resource["group-path"]);
return ( return (
<Skeleton <Skeleton
spinner={state.spinner} spinner={state.spinner}
resources={resources} associations={associations.link}
invites={invites} invites={invites}
groups={groups} groups={groups}
selected={resourcePath} selected={resourcePath}
@ -117,7 +117,7 @@ export class Root extends Component {
resource={resource} resource={resource}
contacts={contacts} contacts={contacts}
contactDetails={contactDetails} contactDetails={contactDetails}
groupPath={resource.group} groupPath={resource["group-path"]}
group={group} group={group}
amOwner={amOwner} amOwner={amOwner}
resourcePath={resourcePath} resourcePath={resourcePath}
@ -132,16 +132,16 @@ export class Root extends Component {
render={ (props) => { render={ (props) => {
const popout = props.match.url.includes("/popout/"); const popout = props.match.url.includes("/popout/");
const resourcePath = '/' + props.match.params.resource; const resourcePath = '/' + props.match.params.resource;
const resource = resources[resourcePath] || false; const resource = associations.link[resourcePath] || false;
const contactDetails = contacts[resource.group] || {}; const contactDetails = contacts[resource["group-path"]] || {};
const group = groups[resource.group] || new Set([]); const group = groups[resource["group-path"]] || new Set([]);
const amOwner = amOwnerOfGroup(resource.group); const amOwner = amOwnerOfGroup(resource["group-path"]);
return ( return (
<Skeleton <Skeleton
spinner={state.spinner} spinner={state.spinner}
resources={resources} associations={associations.link}
invites={invites} invites={invites}
groups={groups} groups={groups}
selected={resourcePath} selected={resourcePath}
@ -153,7 +153,7 @@ export class Root extends Component {
resource={resource} resource={resource}
contacts={contacts} contacts={contacts}
contactDetails={contactDetails} contactDetails={contactDetails}
groupPath={resource.group} groupPath={resource["group-path"]}
group={group} group={group}
amOwner={amOwner} amOwner={amOwner}
resourcePath={resourcePath} resourcePath={resourcePath}
@ -167,11 +167,11 @@ export class Root extends Component {
<Route exact path="/~link/(popout)?/:resource/:page?" <Route exact path="/~link/(popout)?/:resource/:page?"
render={ (props) => { render={ (props) => {
const resourcePath = '/' + props.match.params.resource; const resourcePath = '/' + props.match.params.resource;
const resource = resources[resourcePath] || {}; const resource = associations.link[resourcePath] || {metadata: {}};
const amOwner = amOwnerOfGroup(resource.group); const amOwner = amOwnerOfGroup(resource["group-path"]);
let contactDetails = contacts[resource.group] || {}; let contactDetails = contacts[resource["group-path"]] || {};
let page = props.match.params.page || 0; let page = props.match.params.page || 0;
@ -192,7 +192,7 @@ export class Root extends Component {
return ( return (
<Skeleton <Skeleton
spinner={state.spinner} spinner={state.spinner}
resources={resources} associations={associations.link}
invites={invites} invites={invites}
groups={groups} groups={groups}
selected={resourcePath} selected={resourcePath}
@ -220,13 +220,13 @@ export class Root extends Component {
<Route exact path="/~link/(popout)?/:resource/:page/:index/:encodedUrl/:commentpage?" <Route exact path="/~link/(popout)?/:resource/:page/:index/:encodedUrl/:commentpage?"
render={ (props) => { render={ (props) => {
const resourcePath = '/' + props.match.params.resource; const resourcePath = '/' + props.match.params.resource;
const resource = resources[resourcePath] || {}; const resource = associations.link[resourcePath] || {metadata: {}};
const amOwner = amOwnerOfGroup(resource.group); const amOwner = amOwnerOfGroup(resource["group-path"]);
let popout = props.match.url.includes("/popout/"); let popout = props.match.url.includes("/popout/");
let contactDetails = contacts[resource.group] || {}; let contactDetails = contacts[resource["group-path"]] || {};
let index = props.match.params.index || 0; let index = props.match.params.index || 0;
let page = props.match.params.page || 0; let page = props.match.params.page || 0;
@ -246,7 +246,7 @@ export class Root extends Component {
return ( return (
<Skeleton <Skeleton
spinner={state.spinner} spinner={state.spinner}
resources={resources} associations={associations.link}
invites={invites} invites={invites}
groups={groups} groups={groups}
selected={resourcePath} selected={resourcePath}
@ -262,7 +262,7 @@ export class Root extends Component {
linkIndex={index} linkIndex={index}
contacts={contactDetails} contacts={contactDetails}
resourcePath={resourcePath} resourcePath={resourcePath}
groupPath={resource.group} groupPath={resource["group-path"]}
amOwner={amOwner} amOwner={amOwner}
popout={popout} popout={popout}
sidebarShown={state.sidebarShown} sidebarShown={state.sidebarShown}

View File

@ -29,9 +29,9 @@ export class SettingsScreen extends Component {
componentDidMount() { componentDidMount() {
if (this.props.resource) { if (this.props.resource) {
this.setState({ this.setState({
title: this.props.resource.title, title: this.props.resource.metadata.title,
description: this.props.resource.description, description: this.props.resource.metadata.description,
color: uxToHex(this.props.resource.color || '0x0') color: uxToHex(this.props.resource.metadata.color || '0x0')
}); });
} }
} }
@ -49,9 +49,9 @@ export class SettingsScreen extends Component {
if (props.resource && (prevProps !== props)) { if (props.resource && (prevProps !== props)) {
this.setState({ this.setState({
title: props.resource.title, title: props.resource.metadata.title,
description: props.resource.description, description: props.resource.metadata.description,
color: uxToHex(props.resource.color || '0x0') color: uxToHex(props.resource.metadata.color || '0x0')
}); });
} }
} }
@ -135,9 +135,9 @@ export class SettingsScreen extends Component {
props.resourcePath, props.resourcePath,
props.groupPath, props.groupPath,
state.title, state.title,
props.resource.description, props.resource.metadata.description,
props.resource['date-created'], props.resource.metadata['date-created'],
uxToHex(props.resource.color) uxToHex(props.resource.metadata.color)
).then(() => { ).then(() => {
api.setSpinner(false); api.setSpinner(false);
this.refs.rename.innerText = "Saved"; this.refs.rename.innerText = "Saved";
@ -170,7 +170,7 @@ export class SettingsScreen extends Component {
api.metadataAdd( api.metadataAdd(
props.resourcePath, props.resourcePath,
props.groupPath, props.groupPath,
props.resource.title, props.resource.metadata.title,
state.description, state.description,
props.resource['date-created'], props.resource['date-created'],
uxToHex(props.resource.color) uxToHex(props.resource.color)
@ -204,9 +204,9 @@ export class SettingsScreen extends Component {
api.metadataAdd( api.metadataAdd(
props.resourcePath, props.resourcePath,
props.groupPath, props.groupPath,
props.resource.title, props.resource.metadata.title,
props.resource.description, props.resource.metadata.description,
props.resource['date-created'], props.resource.metadata['date-created'],
state.color state.color
).then(() => { ).then(() => {
api.setSpinner(false); api.setSpinner(false);
@ -252,7 +252,7 @@ export class SettingsScreen extends Component {
<h2 <h2
className="dib f9 fw4 v-top" className="dib f9 fw4 v-top"
style={{ width: "max-content" }}> style={{ width: "max-content" }}>
{props.resource.title} {props.resource.metadata.title}
</h2> </h2>
</Link> </Link>
<LinksTabBar {...props}/> <LinksTabBar {...props}/>
@ -283,7 +283,7 @@ export class SettingsScreen extends Component {
<h2 <h2
className="dib f9 fw4 v-top" className="dib f9 fw4 v-top"
style={{ width: "max-content" }}> style={{ width: "max-content" }}>
{props.resource.title} {props.resource.metadata.title}
</h2> </h2>
</Link> </Link>
<LinksTabBar {...props}/> <LinksTabBar {...props}/>

View File

@ -26,7 +26,7 @@ export class Skeleton extends Component {
<ChannelsSidebar <ChannelsSidebar
active={this.props.active} active={this.props.active}
popout={popout} popout={popout}
resources={this.props.resources} associations={this.props.associations}
invites={this.props.invites} invites={this.props.invites}
groups={this.props.groups} groups={this.props.groups}
selected={this.props.selected} selected={this.props.selected}

View File

@ -6,64 +6,60 @@ export class MetadataReducer {
if (data) { if (data) {
this.associations(data, state); this.associations(data, state);
this.add(data, state); this.add(data, state);
this.remove(data, state);
this.update(data, state); this.update(data, state);
this.remove(data, state);
} }
} }
associations(json, state) { associations(json, state) {
let data = _.get(json, 'associations', false); let data = _.get(json, 'associations', false);
if (data) { if (data) {
let metadata = new Map; let metadata = state.associations;
Object.keys(data).map((key) => { Object.keys(data).map((channel) => {
let assoc = data[key]; let channelObj = data[channel];
if (assoc['app-name'] !== 'link') { let app = data[channel]["app-name"];
return; if (!metadata[app]) {
metadata[app] = {};
} }
if (state.resources[assoc['app-path']]) { metadata[app][channelObj["app-path"]] = channelObj;
console.error('beware! overwriting previous data', data['app-path']); })
} state.associations = metadata;
state.resources[assoc['app-path']] = {
group: assoc['group-path'],
...assoc.metadata
};
});
} }
} }
add(json, state) { add(json, state) {
let data = _.get(json, 'add', false); let data = _.get(json, 'add', false);
if (data) { if (data) {
if (state.resources[data['app-path']]) { let metadata = state.associations;
console.error('beware! overwriting previous data', data['app-path']); let app = data["app-name"];
} if (!metadata[app]) {
this.update({'update-metadata': data}, state); metadata[app] = {};
}
}
remove(json, state) {
let data = _.get(json, 'remove', false);
if (data) {
if (data['app-name'] !== 'link') {
return;
}
const have = state.resources[data['app-path']];
if (have && have.group === data['group-path']) {
delete state.resources[data['app-path']];
} }
metadata[app][data["app-path"]] = data;
state.associations = metadata;
} }
} }
update(json, state) { update(json, state) {
let data = _.get(json, 'update-metadata', false); let data = _.get(json, 'update-metadata', false);
if (data) { if (data) {
if (data['app-name'] !== 'link') { let metadata = state.associations;
return; let app = data["app-name"];
} metadata[app][data["app-path"]] = data;
state.resources[data['app-path']] = { state.associations = metadata;
group: data['group-path'],
...data.metadata
};
} }
} }
}
remove(json, state) {
let data = _.get(json, 'remove', false);
if (data) {
let metadata = state.associations;
let app = data["app-name"];
if (!metadata[app]) {
return false;
}
delete metadata[app][data["app-path"]];
state.associations = metadata;
}
}
}

View File

@ -14,7 +14,10 @@ class Store {
this.state = { this.state = {
contacts: {}, contacts: {},
groups: {}, groups: {},
resources: {}, associations: {
link: {},
contacts: {}
},
invites: {}, invites: {},
links: {}, links: {},
comments: {}, comments: {},

View File

@ -30,6 +30,11 @@ export class Subscription {
this.handleError.bind(this), this.handleError.bind(this),
this.handleQuitAndResubscribe.bind(this) this.handleQuitAndResubscribe.bind(this)
); );
api.bind('/app-name/contacts', 'PUT', api.authTokens.ship, 'metadata-store',
this.handleEvent.bind(this),
this.handleError.bind(this),
this.handleQuitAndResubscribe.bind(this)
);
// open a subscription for all submissions // open a subscription for all submissions
api.getPage('', 0); api.getPage('', 0);