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 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';
@ -12,12 +14,13 @@ import { getServiceUrl } from '../util/config';
* @param {Object} config
* @param {string} [type]
* @param {string} pkg
* @param {string} [text]
*/
const PackageLink = ({ config, type, pkg }) => {
const PackageLink = ({ config, type, pkg, text }) => {
// TODO(burdon): Pass in expected arg types.
if (typeof pkg === 'string') {
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
@ -28,16 +31,17 @@ const PackageLink = ({ config, type, pkg }) => {
Object.keys(pkg[platform]).forEach(arch => {
const cid = pkg[platform][arch];
const ipfsUrl = getServiceUrl(config, 'ipfs.gateway', { path: `${cid}` });
packageLinks.push(
<Link
key={`${cid}`}
href={ipfsUrl}
title={cid}
target='ipfs'
>
{platform}/{arch}: {cid}
</Link>
<div>
<Link
key={`${cid}`}
href={ipfsUrl}
title={cid}
target='ipfs'
>
{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(() => ({
small: {
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 TableCell from '../../../components/TableCell';
import { getServiceUrl } from '../../../util/config';
import AppLink from "../../../components/AppLink";
const AppRecords = () => {
const { config } = useContext(ConsoleContext);
@ -41,27 +42,6 @@ const AppRecords = () => {
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 (
<Table>
<TableHead>
@ -70,22 +50,19 @@ const AppRecords = () => {
<TableCell onClick={sortBy('attributes.displayName')}>Name</TableCell>
<TableCell onClick={sortBy('version')} size='small'>Version</TableCell>
<TableCell onClick={sortBy('createTime')} size='small'>Created</TableCell>
<TableCell size='small'>Downloaded</TableCell>
<TableCell size='icon'>Downloaded</TableCell>
</TableRow>
</TableHead>
<TableBody>
{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 (
<TableRow key={id} size='small'>
<TableCell monospace>
<Link href={appLink} target={name}>{name}</Link>
<AppLink config={config} name={name} />
</TableCell>
<TableCell>{displayName}</TableCell>
<TableCell monospace>
<Link href={verLink} target={version}>{version}</Link>
<AppLink config={config} name={name} version={version} text={version} />
</TableCell>
<TableCell>{moment.utc(createTime).fromNow()}</TableCell>
<TableCell>

View File

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

View File

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