Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions frontend/src/list-json/json-node.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<div>
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
<button
v-if="showToggle"
type="button"
class="w-4 h-4 mr-1 inline-flex items-center justify-center leading-none text-gray-500 hover:text-gray-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-slate-400 cursor-pointer"
@click.stop="handleToggle"
>
{{ isCollapsedNode ? '+' : '-' }}
</button>
<span v-else class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible flex-shrink-0"></span>
<template v-if="hasKey">
<span class="text-blue-600">"{{ nodeKey }}"</span><span>: </span>
</template>
<template v-if="isComplex">
<template v-if="hasChildren">
<span>{{ openingBracket }}</span>
<span v-if="isCollapsedNode" class="mx-1">…</span>
<span v-if="isCollapsedNode">{{ closingBracket }}{{ comma }}</span>
</template>
<template v-else>
<span>{{ openingBracket }}{{ closingBracket }}{{ comma }}</span>
</template>
</template>
<template v-else>
<!--
If value is a string and overflows its container (i.e. goes over one line), show an ellipsis.
This is done via CSS ellipsis strategy.
-->
<span
v-if="shouldShowReferenceLink"
class="inline-flex items-baseline group"
>
<span
:class="[...valueClasses, 'underline', 'decoration-dotted', 'underline-offset-2']"
:style="typeof value === 'string'
? {
display: 'inline-block',
maxWidth: '100%',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
verticalAlign: 'bottom'
}
: {}"
:title="typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined"
>
{{ formattedValue }}
</span>
<span>
{{ comma }}
</span>
<a
href="#"
class="ml-1 text-sm text-sky-700 opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity"
@click.stop.prevent="goToReference(value)"
>
View Document
</a>
</span>
<span
v-else
:class="valueClasses"
:style="typeof value === 'string'
? {
display: 'inline-block',
maxWidth: '100%',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
verticalAlign: 'bottom'
}
: {}"
:title="typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined"
>
{{ formattedValue }}{{ comma }}
</span>
</template>
</div>
<template v-if="isComplex && hasChildren && !isCollapsedNode">
<json-node
v-for="child in children"
:key="child.path"
:node-key="child.displayKey"
:value="child.value"
:level="level + 1"
:is-last="child.isLast"
:path="child.path"
:toggle-collapse="toggleCollapse"
:is-collapsed="isCollapsed"
:create-child-path="createChildPath"
:indent-size="indentSize"
:max-top-level-fields="maxTopLevelFields"
:top-level-expanded="topLevelExpanded"
:expand-top-level="expandTopLevel"
:references="references"
></json-node>
<div
v-if="hasHiddenRootChildren"
class="flex items-baseline whitespace-pre"
:style="indentStyle"
>
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
<button
type="button"
class="text-xs inline-flex items-center gap-1 ml-4 text-slate-500 hover:text-slate-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-slate-400"
:title="hiddenChildrenTooltip"
@click.stop="handleExpandTopLevel"
>
<span aria-hidden="true">{{hiddenChildrenLabel}}…</span>
</button>
</div>
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
<span>{{ closingBracket }}{{ comma }}</span>
</div>
</template>
</div>
1 change: 1 addition & 0 deletions frontend/src/list-json/list-json.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
:max-top-level-fields="maxTopLevelFields"
:top-level-expanded="topLevelExpanded"
:expand-top-level="expandTopLevel"
:references="references"
></json-node>
</div>
</div>
126 changes: 38 additions & 88 deletions frontend/src/list-json/list-json.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,97 +2,19 @@

const template = require('./list-json.html');

const JsonNodeTemplate = `
<div>
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
<button
v-if="showToggle"
type="button"
class="w-4 h-4 mr-1 inline-flex items-center justify-center leading-none text-gray-500 hover:text-gray-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-slate-400 cursor-pointer"
@click.stop="handleToggle"
>
{{ isCollapsedNode ? '+' : '-' }}
</button>
<span v-else class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible flex-shrink-0"></span>
<template v-if="hasKey">
<span class="text-blue-600">"{{ nodeKey }}"</span><span>: </span>
</template>
<template v-if="isComplex">
<template v-if="hasChildren">
<span>{{ openingBracket }}</span>
<span v-if="isCollapsedNode" class="mx-1">…</span>
<span v-if="isCollapsedNode">{{ closingBracket }}{{ comma }}</span>
</template>
<template v-else>
<span>{{ openingBracket }}{{ closingBracket }}{{ comma }}</span>
</template>
</template>
<template v-else>
<!--
If value is a string and overflows its container (i.e. goes over one line), show an ellipsis.
This is done via CSS ellipsis strategy.
-->
<span
:class="valueClasses"
:style="typeof value === 'string'
? {
display: 'inline-block',
maxWidth: '100%',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
verticalAlign: 'bottom'
}
: {}"
:title="typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined"
>
{{ formattedValue }}{{ comma }}
</span>
</template>
</div>
<template v-if="isComplex && hasChildren && !isCollapsedNode">
<json-node
v-for="child in children"
:key="child.path"
:node-key="child.displayKey"
:value="child.value"
:level="level + 1"
:is-last="child.isLast"
:path="child.path"
:toggle-collapse="toggleCollapse"
:is-collapsed="isCollapsed"
:create-child-path="createChildPath"
:indent-size="indentSize"
:max-top-level-fields="maxTopLevelFields"
:top-level-expanded="topLevelExpanded"
:expand-top-level="expandTopLevel"
></json-node>
<div
v-if="hasHiddenRootChildren"
class="flex items-baseline whitespace-pre"
:style="indentStyle"
>
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
<button
type="button"
class="text-xs inline-flex items-center gap-1 ml-4 text-slate-500 hover:text-slate-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-slate-400"
:title="hiddenChildrenTooltip"
@click.stop="handleExpandTopLevel"
>
<span aria-hidden="true">{{hiddenChildrenLabel}}…</span>
</button>
</div>
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
<span>{{ closingBracket }}{{ comma }}</span>
</div>
</template>
</div>
`;
const JsonNodeTemplate = require('./json-node.html');

module.exports = app => app.component('list-json', {
template: template,
props: ['value'],
props: {
value: {
required: true
},
references: {
type: Object,
default: () => ({})
}
},
data() {
return {
collapsedMap: {},
Expand Down Expand Up @@ -196,6 +118,10 @@ module.exports = app => app.component('list-json', {
expandTopLevel: {
type: Function,
default: null
},
references: {
type: Object,
default: () => ({})
}
},
computed: {
Expand Down Expand Up @@ -334,6 +260,24 @@ module.exports = app => app.component('list-json', {
},
hiddenChildrenTooltip() {
return this.hiddenChildrenLabel;
},
normalizedPath() {
if (typeof this.path !== 'string') {
return '';
}
return this.path
.replace(/^root\.?/, '')
.replace(/\[\d+\]/g, '')
.replace(/^\./, '');
},
referenceModel() {
if (!this.normalizedPath || !this.references) {
return null;
}
return this.references[this.normalizedPath] || null;
},
shouldShowReferenceLink() {
return Boolean(this.referenceModel) && typeof this.value === 'string';
}
},
methods: {
Expand All @@ -358,6 +302,12 @@ module.exports = app => app.component('list-json', {
if (this.isRoot && typeof this.expandTopLevel === 'function') {
this.expandTopLevel();
}
},
goToReference(id) {
if (!this.referenceModel) {
return;
}
this.$router.push({ path: `/model/${this.referenceModel}/document/${id}` });
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/models/models.html
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
>
Open this Document
</button>
<list-json :value="filterDocument(document)">
<list-json :value="filterDocument(document)" :references="referenceMap">
</list-json>
</div>
</div>
Expand Down
16 changes: 14 additions & 2 deletions frontend/src/models/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,17 @@ module.exports = app => app.component('models', {

await this.initSearchFromUrl();
},
computed: {
referenceMap() {
const map = {};
for (const path of this.filteredPaths) {
if (path?.ref) {
map[path.path] = path.ref;
}
}
return map;
}
},
methods: {
buildAutocompleteTrie() {
this.autocompleteTrie = new Trie();
Expand Down Expand Up @@ -338,9 +349,10 @@ module.exports = app => app.component('models', {
},
filterDocument(doc) {
const filteredDoc = {};
console.log(doc, this.filteredPaths);
for (let i = 0; i < this.filteredPaths.length; i++) {
filteredDoc[this.filteredPaths[i].path] = doc[this.filteredPaths[i].path];
const path = this.filteredPaths[i].path;
const value = mpath.get(path, doc);
mpath.set(path, value, filteredDoc);
}
return filteredDoc;
},
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"archetype": "0.13.1",
"csv-stringify": "6.3.0",
"ejson": "^2.2.3",
"extrovert": "^0.1.0",
"extrovert": "^0.2.0",
"marked": "15.0.12",
"node-inspect-extracted": "3.x",
"tailwindcss": "3.4.0",
Expand All @@ -32,7 +32,7 @@
"eslint": "9.30.0",
"express": "4.x",
"mocha": "10.2.0",
"mongoose": "8.x"
"mongoose": "9.x"
},
"scripts": {
"lint": "eslint .",
Expand Down