Splore Blobs and more (#2279)

- Display the prolly-tree for Blobs
- Fix fallout from sha1-xxx to xxxx
- Make the hashes links to splore rooted at that hash

Fixes #2218
Fixes #1321
This commit is contained in:
Erik Arvidsson
2016-08-05 11:41:33 -07:00
committed by GitHub
parent 8c5de64bda
commit 6b6c409d16
3 changed files with 60 additions and 58 deletions

View File

@@ -13,7 +13,7 @@ type Props = {
data: NodeGraph,
onNodeClick: (e: MouseEvent, s: string) => void,
tree: TreeNode,
nomsStore: string,
db: string,
}
export default function Layout(props: Props) : React.Element {
@@ -21,7 +21,7 @@ export default function Layout(props: Props) : React.Element {
const edges = [];
const lookup = {};
const spaceX = 75;
const spaceX = 100;
const spaceY = 20;
const paddingRight = 250;
const getX = d => d.y * spaceX;
@@ -56,7 +56,7 @@ export default function Layout(props: Props) : React.Element {
canOpen={hasChildren}
isOpen={!hasChildren || Boolean(treeNode.data.isOpen)}
hash={hash}
nomsStore={props.nomsStore}
db={props.db}
onClick={(e) => props.onNodeClick(e, treeNode.id)}/>);
children.push(n);
lookup[treeNode.id] = treeNode;

View File

@@ -9,25 +9,25 @@ import React from 'react';
import ReactDOM from 'react-dom';
import {
Blob,
Collection,
Database,
Hash,
HttpBatchStore,
IndexedMetaSequence,
invariant,
kindToString,
List,
ListLeafSequence,
Map,
MapLeafSequence,
OrderedMetaSequence,
Ref,
Set,
SetLeafSequence,
Struct,
StructMirror,
} from '@attic/noms';
import type {StructFieldMirror} from '@attic/noms';
import type {StructFieldMirror, Value} from '@attic/noms';
import {layout, TreeNode} from './buchheim.js';
import type {NodeGraph} from './buchheim.js';
import {filesize} from 'humanize';
const data: NodeGraph = {nodes: {}, links: {}};
let rootHash: Hash;
@@ -71,7 +71,7 @@ function load() {
};
if (params.hash) {
const hash = Hash.parse(params.ref);
const hash = Hash.parse(params.hash);
invariant(hash);
setRootHash(hash);
} else {
@@ -84,7 +84,7 @@ function formatKeyString(v: any): string {
v = v.targetHash;
}
if (v instanceof Hash) {
return v.toString().substring(5, 11);
return v.toString().substring(0, 10);
}
return String(v);
@@ -100,7 +100,6 @@ function handleChunkLoad(hash: Hash, val: any, fromHash: ?string) {
const kid = process(hash, formatKeyString(tuple.ref), id);
if (kid) {
data.nodes[kid].isOpen = true;
process(hash, tuple.ref, kid);
} else {
throw new Error('No kid id.');
@@ -135,51 +134,40 @@ function handleChunkLoad(hash: Hash, val: any, fromHash: ?string) {
if (t === 'boolean' || t === 'number' || t === 'string') {
data.nodes[id] = {name: String(val)};
} else if (val instanceof Blob) {
data.nodes[id] = {name: `Blob (${val.length})`};
} else if (val instanceof List) {
const sequence = val.sequence;
if (sequence instanceof ListLeafSequence) {
data.nodes[id] = {name: `List (${val.length})`};
sequence.items.forEach(c => process(hash, c, id));
} else if (val instanceof Collection) {
const {sequence} = val;
const ks = kindToString(val.type.kind);
const size = getSize(val);
if (sequence instanceof IndexedMetaSequence) {
const name = `${ks}Node (${size})`;
processMetaSequence(id, sequence, name);
} else if (sequence instanceof OrderedMetaSequence) {
const name = `${ks}Node (${size})`;
processMetaSequence(id, sequence, name);
} else {
invariant(sequence instanceof IndexedMetaSequence);
processMetaSequence(id, sequence, 'ListNode');
}
} else if (val instanceof Set) {
const sequence = val.sequence;
if (sequence instanceof SetLeafSequence) {
data.nodes[id] = {name: `Set (${val.size})`};
sequence.items.forEach(c => process(hash, c, id));
} else {
invariant(sequence instanceof OrderedMetaSequence);
processMetaSequence(id, sequence, 'SetNode');
}
} else if (val instanceof Map) {
const sequence = val.sequence;
if (sequence instanceof MapLeafSequence) {
data.nodes[id] = {name: `Map (${val.size})`};
sequence.items.forEach(entry => {
const [k, v] = entry;
// TODO: handle non-string keys
const kid = process(hash, k, id);
if (kid) {
data.nodes[kid].isOpen = true;
process(hash, v, kid);
} else {
throw new Error('No kid id.');
}
});
} else {
invariant(sequence instanceof OrderedMetaSequence);
processMetaSequence(id, sequence, 'MapNode');
const name = `${ks} (${size})`;
data.nodes[id] = {name};
if (val instanceof Map) {
sequence.items.forEach(entry => {
const [k, v] = entry;
// TODO: handle non-string keys
const kid = process(hash, k, id);
if (kid) {
data.nodes[kid].isOpen = true;
process(hash, v, kid);
} else {
throw new Error('No kid id.');
}
});
} else {
sequence.items.forEach(c => process(hash, c, id));
}
}
} else if (val instanceof Hash) {
const refStr = val.toString();
data.nodes[id] = {
canOpen: true,
name: refStr.substr(5, 6),
name: refStr.substr(0, 10),
hash: val,
};
} else if (val instanceof Struct) {
@@ -257,9 +245,9 @@ class Prompt extends React.Component<void, {}, void> {
defaultValue={params.token}
placeholder='auth token'
/>
<input type='text' ref='ref' style={inputStyle}
defaultValue={params.ref}
placeholder='sha1-xyz (ref to jump to)'
<input type='text' ref='hash' style={inputStyle}
defaultValue={params.hash}
placeholder='0123456789abcdefghijklmnopqrstuv (hash to jump to)'
/>
<button type='submit'>OK</button>
</form>
@@ -269,13 +257,13 @@ class Prompt extends React.Component<void, {}, void> {
_handleOnSubmit(e) {
e.preventDefault();
const {db, token, ref} = this.refs;
const {db, token, hash} = this.refs;
let qs = '?db=' + db.value;
if (token.value) {
qs += '&token=' + token.value;
}
if (ref.value) {
qs += '&ref=' + ref.value;
if (hash.value) {
qs += '&hash=' + hash.value;
}
window.history.pushState({}, undefined, qs);
load();
@@ -290,6 +278,20 @@ function render() {
const dt = new TreeNode(data, rootHash.toString(), null, 0, 0, {});
layout(dt);
ReactDOM.render(
<Layout tree={dt} data={data} onNodeClick={handleNodeClick} nomsStore={params.db}/>,
<Layout tree={dt} data={data} onNodeClick={handleNodeClick} db={params.db}/>,
renderNode);
}
function getSize(val: Value): string | number {
// This was extracted into a function to work around a bug in Flow.
if (val instanceof List) {
return val.length;
}
if (val instanceof Map || val instanceof Set) {
return val.size;
}
if (val instanceof Blob) {
return filesize(val.length);
}
throw new Error('unreachable');
}

View File

@@ -20,7 +20,7 @@ type Props = {
y: number,
spaceX: number,
hash: ?Hash,
nomsStore: string,
db: string,
onClick: (e: MouseEvent, s: String) => void,
};
@@ -54,7 +54,7 @@ export default class Node extends React.Component<void, Props, State> {
let text = this.props.text;
if (this.props.hash) {
const url = `${this.props.nomsStore}/ref/${this.props.hash.toString()}`;
const url = `/?db=${this.props.db}&hash=${this.props.hash.toString()}`;
text = <a href={url}>{text}</a>;
}