WNS info links

This commit is contained in:
Thomas E Lackey 2020-06-09 22:34:52 -05:00
parent c831181c1d
commit 432c061952
7 changed files with 152 additions and 59 deletions

View File

@ -0,0 +1,42 @@
//
// Copyright 2020 DxOS.org.org
//
import React from 'react';
import Link from '@material-ui/core/Link';
import { getServiceUrl } from '../util/config';
const getAppUrl = (config, { name, version, text }) => {
const base = getServiceUrl(config, 'app.server');
const pathComponents = [base];
// TODO(burdon): Fix.
// `wire app serve` expects the /wrn/ prefix.
// That is OK in the production config where we can make it part of the the route,
// but in development it must be prepended since we don't want to make it part of services.app.server.
if (!base.startsWith(`/${config.services.app.prefix}`) && !base.endsWith(`/${config.services.app.prefix}`)) {
pathComponents.push(config.services.app.prefix.substring(1));
}
if (version) {
pathComponents.push(`${name}@${version}`);
} else {
pathComponents.push(name);
}
return `${pathComponents.join('/')}/`;
};
/**
* Render link to record in WNS.
* @param {Object} config
* @param {string} name
* @param {string} [text]
* @param {string} [version]
*/
const AppLink = ({ config, name, version, text }) => {
const fullURL = getAppUrl(config, {name, version});
return <Link href={fullURL} target={name}>{text || name}</Link>;
};
export default AppLink;

View File

@ -4,6 +4,8 @@
import React from 'react'; import React from 'react';
import Link from '@material-ui/core/Link'; import Link from '@material-ui/core/Link';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import { getServiceUrl } from '../util/config'; import { getServiceUrl } from '../util/config';
@ -12,12 +14,13 @@ import { getServiceUrl } from '../util/config';
* @param {Object} config * @param {Object} config
* @param {string} [type] * @param {string} [type]
* @param {string} pkg * @param {string} pkg
* @param {string} [text]
*/ */
const PackageLink = ({ config, type, pkg }) => { const PackageLink = ({ config, type, pkg, text }) => {
// TODO(burdon): Pass in expected arg types. // TODO(burdon): Pass in expected arg types.
if (typeof pkg === 'string') { if (typeof pkg === 'string') {
const ipfsUrl = getServiceUrl(config, 'ipfs.gateway', { path: `${pkg}` }); const ipfsUrl = getServiceUrl(config, 'ipfs.gateway', { path: `${pkg}` });
return <Link href={ipfsUrl} target='ipfs'>{pkg}</Link>; return <Link href={ipfsUrl} target='ipfs'>{text || pkg}</Link>;
} }
// eslint-disable-next-line default-case // eslint-disable-next-line default-case
@ -28,16 +31,17 @@ const PackageLink = ({ config, type, pkg }) => {
Object.keys(pkg[platform]).forEach(arch => { Object.keys(pkg[platform]).forEach(arch => {
const cid = pkg[platform][arch]; const cid = pkg[platform][arch];
const ipfsUrl = getServiceUrl(config, 'ipfs.gateway', { path: `${cid}` }); const ipfsUrl = getServiceUrl(config, 'ipfs.gateway', { path: `${cid}` });
packageLinks.push( packageLinks.push(
<Link <div>
key={`${cid}`} <Link
href={ipfsUrl} key={`${cid}`}
title={cid} href={ipfsUrl}
target='ipfs' title={cid}
> target='ipfs'
{platform}/{arch}: {cid} >
</Link> {platform}/{arch}
</Link>
</div>
); );
}); });
}); });

View File

@ -0,0 +1,38 @@
//
// Copyright 2020 DxOS.org.org
//
import React from 'react';
import ExitToApp from '@material-ui/icons/ExitToApp';
import Link from '@material-ui/core/Link';
import { getServiceUrl } from '../util/config';
const QUERY = `{
queryRecords(attributes: [
{ key: "name", value: { string: "%NAME%" }}]) {
id type name bondId createTime expiryTime owners attributes { key, value { string, json } }
}
}`;
/**
* Render link to record in WNS.
* @param {Object} config
* @param {string} name
* @param {string} [text]
*/
const QueryLink = ({ config, name, text, icon = false}) => {
const baseURL = getServiceUrl(config, 'wns.webui');
const query = QUERY.replace('%NAME%', name);
const fullURL= encodeURI(`${baseURL}?query=${query}`);
if (icon) {
return <Link href={fullURL} target='wns'>
<ExitToApp />
</Link>
}
return <Link href={fullURL} target='wns'>{text || name}</Link>;
};
export default QueryLink;

View File

@ -11,6 +11,12 @@ import { makeStyles } from '@material-ui/core';
const useStyles = makeStyles(() => ({ const useStyles = makeStyles(() => ({
small: { small: {
width: 160 width: 160
},
medium: {
width: 220
},
icon: {
width: 120
} }
})); }));

View File

@ -20,6 +20,7 @@ import { BooleanIcon } from '../../../components/BooleanIcon';
import Table from '../../../components/Table'; import Table from '../../../components/Table';
import TableCell from '../../../components/TableCell'; import TableCell from '../../../components/TableCell';
import { getServiceUrl } from '../../../util/config'; import { getServiceUrl } from '../../../util/config';
import AppLink from "../../../components/AppLink";
const AppRecords = () => { const AppRecords = () => {
const { config } = useContext(ConsoleContext); const { config } = useContext(ConsoleContext);
@ -41,27 +42,6 @@ const AppRecords = () => {
const localRefs = new Set(ipfsData.refs.local); const localRefs = new Set(ipfsData.refs.local);
// TODO(burdon): Test if app is deployed.
const getAppUrl = ({ name, version }) => {
const base = getServiceUrl(config, 'app.server');
const pathComponents = [base];
// TODO(burdon): Fix.
// `wire app serve` expects the /wrn/ prefix.
// That is OK in the production config where we can make it part of the the route,
// but in development it must be prepended since we don't want to make it part of services.app.server.
if (!base.startsWith(`/${config.services.app.prefix}`) && !base.endsWith(`/${config.services.app.prefix}`)) {
pathComponents.push(config.services.app.prefix.substring(1));
}
if (version) {
pathComponents.push(`${name}@${version}`);
} else {
pathComponents.push(name);
}
return `${pathComponents.join('/')}/`;
};
return ( return (
<Table> <Table>
<TableHead> <TableHead>
@ -70,22 +50,19 @@ const AppRecords = () => {
<TableCell onClick={sortBy('attributes.displayName')}>Name</TableCell> <TableCell onClick={sortBy('attributes.displayName')}>Name</TableCell>
<TableCell onClick={sortBy('version')} size='small'>Version</TableCell> <TableCell onClick={sortBy('version')} size='small'>Version</TableCell>
<TableCell onClick={sortBy('createTime')} size='small'>Created</TableCell> <TableCell onClick={sortBy('createTime')} size='small'>Created</TableCell>
<TableCell size='small'>Downloaded</TableCell> <TableCell size='icon'>Downloaded</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{appData.sort(sorter).map(({ id, name, version, createTime, attributes: { displayName, publicUrl, package: hash } }) => { {appData.sort(sorter).map(({ id, name, version, createTime, attributes: { displayName, publicUrl, package: hash } }) => {
const verLink = getAppUrl({ id, name, version, publicUrl });
const appLink = getAppUrl({ id, name, publicUrl });
return ( return (
<TableRow key={id} size='small'> <TableRow key={id} size='small'>
<TableCell monospace> <TableCell monospace>
<Link href={appLink} target={name}>{name}</Link> <AppLink config={config} name={name} />
</TableCell> </TableCell>
<TableCell>{displayName}</TableCell> <TableCell>{displayName}</TableCell>
<TableCell monospace> <TableCell monospace>
<Link href={verLink} target={version}>{version}</Link> <AppLink config={config} name={name} version={version} text={version} />
</TableCell> </TableCell>
<TableCell>{moment.utc(createTime).fromNow()}</TableCell> <TableCell>{moment.utc(createTime).fromNow()}</TableCell>
<TableCell> <TableCell>

View File

@ -122,9 +122,9 @@ const IPFS = () => {
<Table stickyHeader size='small' className={classes.table}> <Table stickyHeader size='small' className={classes.table}>
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell size=''>Identifier</TableCell> <TableCell>Identifier</TableCell>
<TableCell size='small'>Description</TableCell> <TableCell size='medium'>Description</TableCell>
<TableCell size='small'>Connected</TableCell> <TableCell size='icon'>Connected</TableCell>
<TableCell>Address</TableCell> <TableCell>Address</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>

View File

@ -11,6 +11,7 @@ import Button from '@material-ui/core/Button';
import TableHead from '@material-ui/core/TableHead'; import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow'; import TableRow from '@material-ui/core/TableRow';
import TableBody from '@material-ui/core/TableBody'; import TableBody from '@material-ui/core/TableBody';
import Tooltip from '@material-ui/core/Tooltip';
import WNS_RECORDS from '../../../gql/wns_records.graphql'; import WNS_RECORDS from '../../../gql/wns_records.graphql';
@ -20,6 +21,8 @@ import Table from '../../../components/Table';
import TableCell from '../../../components/TableCell'; import TableCell from '../../../components/TableCell';
import PackageLink from '../../../components/PackageLink'; import PackageLink from '../../../components/PackageLink';
import QueryLink from "../../../components/QueryLink";
import AppLink from "../../../components/AppLink";
const types = [ const types = [
{ key: null, label: 'ALL' }, { key: null, label: 'ALL' },
@ -67,14 +70,14 @@ const WNSRecords = ({ type }) => {
const [sorter, sortBy] = useSorter('createTime', false); const [sorter, sortBy] = useSorter('createTime', false);
const data = useQueryStatusReducer(useQuery(WNS_RECORDS, { const data = useQueryStatusReducer(useQuery(WNS_RECORDS, {
pollInterval: config.api.intervalQuery, pollInterval: config.api.intervalQuery,
variables: { type } variables: { attributes: { type } }
})); }));
if (!data) { if (!data) {
return null; return null;
} }
const records = data.wns_records.json; const records = JSON.parse(data.wns_records.json);
return ( return (
<Table> <Table>
@ -82,28 +85,51 @@ const WNSRecords = ({ type }) => {
<TableRow> <TableRow>
<TableCell onClick={sortBy('type')} size='small'>Type</TableCell> <TableCell onClick={sortBy('type')} size='small'>Type</TableCell>
<TableCell onClick={sortBy('name')}>Identifier</TableCell> <TableCell onClick={sortBy('name')}>Identifier</TableCell>
<TableCell size='icon'>Query</TableCell>
<TableCell onClick={sortBy('attributes.displayName')}>Name</TableCell>
<TableCell onClick={sortBy('version')} size='small'>Version</TableCell> <TableCell onClick={sortBy('version')} size='small'>Version</TableCell>
<TableCell onClick={sortBy('createTime')} size='small'>Created</TableCell> <TableCell onClick={sortBy('createTime')} size='small'>Created</TableCell>
<TableCell onClick={sortBy('attributes.displayName')}>Name</TableCell> <TableCell onClick={sortBy('package')} size='small'>Package</TableCell>
<TableCell onClick={sortBy('attributes.package')}>Package Hash</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{records.sort(sorter) {records.sort(sorter)
.map(({ id, type, name, version, createTime, attributes: { displayName, package: pkg } }) => ( .map((record) => {
<TableRow key={id} size='small'> const { id, type, name, version, createTime, attributes: { displayName, description, service, package: pkg } } = record;
<TableCell monospace>{type}</TableCell>
<TableCell monospace>{name}</TableCell> let pkgLink = undefined;
<TableCell monospace>{version}</TableCell> let appLink = undefined;
<TableCell>{moment.utc(createTime).fromNow()}</TableCell> let verLink = undefined;
<TableCell>{displayName}</TableCell>
<TableCell title={JSON.stringify(pkg)} monospace> if (pkg) {
{pkg && ( pkgLink = (<PackageLink config={config} type={type} pkg={pkg}/>);
<PackageLink config={config} type={type} pkg={pkg} /> }
)}
</TableCell> if (type === 'wrn:app') {
</TableRow> appLink = (<AppLink config={config} name={name}/>);
))} verLink = (<AppLink config={config} name={name} version={version} text={version}/>);
}
return (<TableRow key={id} size='small'>
<TableCell monospace>{type}</TableCell>
<TableCell monospace>
{appLink && appLink || name}
</TableCell>
<TableCell>
<QueryLink config={config} name={name} icon={true}/>
</TableCell>
<TableCell>{displayName || service || description}</TableCell>
<TableCell monospace>
{verLink && verLink || version}
</TableCell>
<TableCell>{moment.utc(createTime).fromNow()}</TableCell>
<TableCell monospace>
{pkgLink}
</TableCell>
</TableRow>
);
}
)}
</TableBody> </TableBody>
</Table> </Table>
); );