@mongoosejs/studio 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/frontend/public/app.js +90 -93
- package/frontend/public/tw.css +21 -0
- package/frontend/src/dashboard/dashboard.js +23 -0
- package/frontend/src/list-json/json-node.html +118 -0
- package/frontend/src/list-json/list-json.html +1 -0
- package/frontend/src/list-json/list-json.js +38 -88
- package/frontend/src/models/models.html +1 -1
- package/frontend/src/models/models.js +14 -2
- package/package.json +4 -4
package/frontend/public/app.js
CHANGED
|
@@ -128,6 +128,7 @@ var map = {
|
|
|
128
128
|
"./list-default/list-default.css": "./frontend/src/list-default/list-default.css",
|
|
129
129
|
"./list-default/list-default.html": "./frontend/src/list-default/list-default.html",
|
|
130
130
|
"./list-default/list-default.js": "./frontend/src/list-default/list-default.js",
|
|
131
|
+
"./list-json/json-node.html": "./frontend/src/list-json/json-node.html",
|
|
131
132
|
"./list-json/list-json": "./frontend/src/list-json/list-json.js",
|
|
132
133
|
"./list-json/list-json.html": "./frontend/src/list-json/list-json.html",
|
|
133
134
|
"./list-json/list-json.js": "./frontend/src/list-json/list-json.js",
|
|
@@ -1791,6 +1792,25 @@ module.exports = app => app.component('dashboard', {
|
|
|
1791
1792
|
} finally {
|
|
1792
1793
|
this.status = 'loaded';
|
|
1793
1794
|
}
|
|
1795
|
+
},
|
|
1796
|
+
shouldEvaluateDashboard() {
|
|
1797
|
+
if (this.dashboardResults.length === 0) {
|
|
1798
|
+
return true;
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
const finishedEvaluatingAt = this.dashboardResults[0].finishedEvaluatingAt;
|
|
1802
|
+
if (!finishedEvaluatingAt) {
|
|
1803
|
+
return true;
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
const sixHoursAgo = Date.now() - 6 * 60 * 60 * 1000;
|
|
1807
|
+
const finishedAt = new Date(finishedEvaluatingAt).getTime();
|
|
1808
|
+
|
|
1809
|
+
if (Number.isNaN(finishedAt)) {
|
|
1810
|
+
return true;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
return finishedAt < sixHoursAgo;
|
|
1794
1814
|
}
|
|
1795
1815
|
},
|
|
1796
1816
|
computed: {
|
|
@@ -1809,6 +1829,10 @@ module.exports = app => app.component('dashboard', {
|
|
|
1809
1829
|
this.title = this.dashboard.title;
|
|
1810
1830
|
this.description = this.dashboard.description ?? '';
|
|
1811
1831
|
this.dashboardResults = dashboardResults;
|
|
1832
|
+
if (this.shouldEvaluateDashboard()) {
|
|
1833
|
+
await this.evaluateDashboard();
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1812
1836
|
this.status = 'loaded';
|
|
1813
1837
|
}
|
|
1814
1838
|
});
|
|
@@ -3888,6 +3912,17 @@ module.exports = app => app.component('list-default', {
|
|
|
3888
3912
|
|
|
3889
3913
|
/***/ }),
|
|
3890
3914
|
|
|
3915
|
+
/***/ "./frontend/src/list-json/json-node.html":
|
|
3916
|
+
/*!***********************************************!*\
|
|
3917
|
+
!*** ./frontend/src/list-json/json-node.html ***!
|
|
3918
|
+
\***********************************************/
|
|
3919
|
+
/***/ ((module) => {
|
|
3920
|
+
|
|
3921
|
+
"use strict";
|
|
3922
|
+
module.exports = "<div>\n <div class=\"flex items-baseline whitespace-pre\" :style=\"indentStyle\">\n <button\n v-if=\"showToggle\"\n type=\"button\"\n 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\"\n @click.stop=\"handleToggle\"\n >\n {{ isCollapsedNode ? '+' : '-' }}\n </button>\n <span v-else class=\"w-4 h-4 mr-1 inline-flex items-center justify-center invisible flex-shrink-0\"></span>\n <template v-if=\"hasKey\">\n <span class=\"text-blue-600\">\"{{ nodeKey }}\"</span><span>: </span>\n </template>\n <template v-if=\"isComplex\">\n <template v-if=\"hasChildren\">\n <span>{{ openingBracket }}</span>\n <span v-if=\"isCollapsedNode\" class=\"mx-1\">…</span>\n <span v-if=\"isCollapsedNode\">{{ closingBracket }}{{ comma }}</span>\n </template>\n <template v-else>\n <span>{{ openingBracket }}{{ closingBracket }}{{ comma }}</span>\n </template>\n </template>\n <template v-else>\n <!--\n If value is a string and overflows its container (i.e. goes over one line), show an ellipsis.\n This is done via CSS ellipsis strategy.\n -->\n <span\n v-if=\"shouldShowReferenceLink\"\n class=\"inline-flex items-baseline group\"\n >\n <span\n :class=\"[...valueClasses, 'underline', 'decoration-dotted', 'underline-offset-2']\"\n :style=\"typeof value === 'string'\n ? {\n display: 'inline-block',\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n verticalAlign: 'bottom'\n }\n : {}\"\n :title=\"typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined\"\n >\n {{ formattedValue }}\n </span>\n <span>\n {{ comma }}\n </span>\n <a\n href=\"#\"\n class=\"ml-1 text-sm text-sky-700 opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity\"\n @click.stop.prevent=\"goToReference(value)\"\n >\n View Document\n </a>\n </span>\n <span\n v-else\n :class=\"valueClasses\"\n :style=\"typeof value === 'string'\n ? {\n display: 'inline-block',\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n verticalAlign: 'bottom'\n }\n : {}\"\n :title=\"typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined\"\n >\n {{ formattedValue }}{{ comma }}\n </span>\n </template>\n </div>\n <template v-if=\"isComplex && hasChildren && !isCollapsedNode\">\n <json-node\n v-for=\"child in children\"\n :key=\"child.path\"\n :node-key=\"child.displayKey\"\n :value=\"child.value\"\n :level=\"level + 1\"\n :is-last=\"child.isLast\"\n :path=\"child.path\"\n :toggle-collapse=\"toggleCollapse\"\n :is-collapsed=\"isCollapsed\"\n :create-child-path=\"createChildPath\"\n :indent-size=\"indentSize\"\n :max-top-level-fields=\"maxTopLevelFields\"\n :top-level-expanded=\"topLevelExpanded\"\n :expand-top-level=\"expandTopLevel\"\n :references=\"references\"\n ></json-node>\n <div\n v-if=\"hasHiddenRootChildren\"\n class=\"flex items-baseline whitespace-pre\"\n :style=\"indentStyle\"\n >\n <span class=\"w-4 h-4 mr-1 inline-flex items-center justify-center invisible\"></span>\n <button\n type=\"button\"\n 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\"\n :title=\"hiddenChildrenTooltip\"\n @click.stop=\"handleExpandTopLevel\"\n >\n <span aria-hidden=\"true\">{{hiddenChildrenLabel}}…</span>\n </button>\n </div>\n <div class=\"flex items-baseline whitespace-pre\" :style=\"indentStyle\">\n <span class=\"w-4 h-4 mr-1 inline-flex items-center justify-center invisible\"></span>\n <span>{{ closingBracket }}{{ comma }}</span>\n </div>\n </template>\n</div>\n";
|
|
3923
|
+
|
|
3924
|
+
/***/ }),
|
|
3925
|
+
|
|
3891
3926
|
/***/ "./frontend/src/list-json/list-json.html":
|
|
3892
3927
|
/*!***********************************************!*\
|
|
3893
3928
|
!*** ./frontend/src/list-json/list-json.html ***!
|
|
@@ -3895,7 +3930,7 @@ module.exports = app => app.component('list-default', {
|
|
|
3895
3930
|
/***/ ((module) => {
|
|
3896
3931
|
|
|
3897
3932
|
"use strict";
|
|
3898
|
-
module.exports = "<div class=\"tooltip w-full font-mono text-sm py-3 text-slate-800\">\n <div class=\"w-full\">\n <json-node\n :node-key=\"null\"\n :value=\"value\"\n :level=\"0\"\n :is-last=\"true\"\n path=\"root\"\n :toggle-collapse=\"toggleCollapse\"\n :is-collapsed=\"isPathCollapsed\"\n :create-child-path=\"createChildPath\"\n :indent-size=\"indentSize\"\n :max-top-level-fields=\"maxTopLevelFields\"\n :top-level-expanded=\"topLevelExpanded\"\n :expand-top-level=\"expandTopLevel\"\n ></json-node>\n </div>\n</div>\n";
|
|
3933
|
+
module.exports = "<div class=\"tooltip w-full font-mono text-sm py-3 text-slate-800\">\n <div class=\"w-full\">\n <json-node\n :node-key=\"null\"\n :value=\"value\"\n :level=\"0\"\n :is-last=\"true\"\n path=\"root\"\n :toggle-collapse=\"toggleCollapse\"\n :is-collapsed=\"isPathCollapsed\"\n :create-child-path=\"createChildPath\"\n :indent-size=\"indentSize\"\n :max-top-level-fields=\"maxTopLevelFields\"\n :top-level-expanded=\"topLevelExpanded\"\n :expand-top-level=\"expandTopLevel\"\n :references=\"references\"\n ></json-node>\n </div>\n</div>\n";
|
|
3899
3934
|
|
|
3900
3935
|
/***/ }),
|
|
3901
3936
|
|
|
@@ -3910,97 +3945,19 @@ module.exports = "<div class=\"tooltip w-full font-mono text-sm py-3 text-slate-
|
|
|
3910
3945
|
|
|
3911
3946
|
const template = __webpack_require__(/*! ./list-json.html */ "./frontend/src/list-json/list-json.html");
|
|
3912
3947
|
|
|
3913
|
-
const JsonNodeTemplate =
|
|
3914
|
-
<div>
|
|
3915
|
-
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
|
|
3916
|
-
<button
|
|
3917
|
-
v-if="showToggle"
|
|
3918
|
-
type="button"
|
|
3919
|
-
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"
|
|
3920
|
-
@click.stop="handleToggle"
|
|
3921
|
-
>
|
|
3922
|
-
{{ isCollapsedNode ? '+' : '-' }}
|
|
3923
|
-
</button>
|
|
3924
|
-
<span v-else class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible flex-shrink-0"></span>
|
|
3925
|
-
<template v-if="hasKey">
|
|
3926
|
-
<span class="text-blue-600">"{{ nodeKey }}"</span><span>: </span>
|
|
3927
|
-
</template>
|
|
3928
|
-
<template v-if="isComplex">
|
|
3929
|
-
<template v-if="hasChildren">
|
|
3930
|
-
<span>{{ openingBracket }}</span>
|
|
3931
|
-
<span v-if="isCollapsedNode" class="mx-1">…</span>
|
|
3932
|
-
<span v-if="isCollapsedNode">{{ closingBracket }}{{ comma }}</span>
|
|
3933
|
-
</template>
|
|
3934
|
-
<template v-else>
|
|
3935
|
-
<span>{{ openingBracket }}{{ closingBracket }}{{ comma }}</span>
|
|
3936
|
-
</template>
|
|
3937
|
-
</template>
|
|
3938
|
-
<template v-else>
|
|
3939
|
-
<!--
|
|
3940
|
-
If value is a string and overflows its container (i.e. goes over one line), show an ellipsis.
|
|
3941
|
-
This is done via CSS ellipsis strategy.
|
|
3942
|
-
-->
|
|
3943
|
-
<span
|
|
3944
|
-
:class="valueClasses"
|
|
3945
|
-
:style="typeof value === 'string'
|
|
3946
|
-
? {
|
|
3947
|
-
display: 'inline-block',
|
|
3948
|
-
maxWidth: '100%',
|
|
3949
|
-
overflow: 'hidden',
|
|
3950
|
-
textOverflow: 'ellipsis',
|
|
3951
|
-
whiteSpace: 'nowrap',
|
|
3952
|
-
verticalAlign: 'bottom'
|
|
3953
|
-
}
|
|
3954
|
-
: {}"
|
|
3955
|
-
:title="typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined"
|
|
3956
|
-
>
|
|
3957
|
-
{{ formattedValue }}{{ comma }}
|
|
3958
|
-
</span>
|
|
3959
|
-
</template>
|
|
3960
|
-
</div>
|
|
3961
|
-
<template v-if="isComplex && hasChildren && !isCollapsedNode">
|
|
3962
|
-
<json-node
|
|
3963
|
-
v-for="child in children"
|
|
3964
|
-
:key="child.path"
|
|
3965
|
-
:node-key="child.displayKey"
|
|
3966
|
-
:value="child.value"
|
|
3967
|
-
:level="level + 1"
|
|
3968
|
-
:is-last="child.isLast"
|
|
3969
|
-
:path="child.path"
|
|
3970
|
-
:toggle-collapse="toggleCollapse"
|
|
3971
|
-
:is-collapsed="isCollapsed"
|
|
3972
|
-
:create-child-path="createChildPath"
|
|
3973
|
-
:indent-size="indentSize"
|
|
3974
|
-
:max-top-level-fields="maxTopLevelFields"
|
|
3975
|
-
:top-level-expanded="topLevelExpanded"
|
|
3976
|
-
:expand-top-level="expandTopLevel"
|
|
3977
|
-
></json-node>
|
|
3978
|
-
<div
|
|
3979
|
-
v-if="hasHiddenRootChildren"
|
|
3980
|
-
class="flex items-baseline whitespace-pre"
|
|
3981
|
-
:style="indentStyle"
|
|
3982
|
-
>
|
|
3983
|
-
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
|
|
3984
|
-
<button
|
|
3985
|
-
type="button"
|
|
3986
|
-
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"
|
|
3987
|
-
:title="hiddenChildrenTooltip"
|
|
3988
|
-
@click.stop="handleExpandTopLevel"
|
|
3989
|
-
>
|
|
3990
|
-
<span aria-hidden="true">{{hiddenChildrenLabel}}…</span>
|
|
3991
|
-
</button>
|
|
3992
|
-
</div>
|
|
3993
|
-
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
|
|
3994
|
-
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
|
|
3995
|
-
<span>{{ closingBracket }}{{ comma }}</span>
|
|
3996
|
-
</div>
|
|
3997
|
-
</template>
|
|
3998
|
-
</div>
|
|
3999
|
-
`;
|
|
3948
|
+
const JsonNodeTemplate = __webpack_require__(/*! ./json-node.html */ "./frontend/src/list-json/json-node.html");
|
|
4000
3949
|
|
|
4001
3950
|
module.exports = app => app.component('list-json', {
|
|
4002
3951
|
template: template,
|
|
4003
|
-
props:
|
|
3952
|
+
props: {
|
|
3953
|
+
value: {
|
|
3954
|
+
required: true
|
|
3955
|
+
},
|
|
3956
|
+
references: {
|
|
3957
|
+
type: Object,
|
|
3958
|
+
default: () => ({})
|
|
3959
|
+
}
|
|
3960
|
+
},
|
|
4004
3961
|
data() {
|
|
4005
3962
|
return {
|
|
4006
3963
|
collapsedMap: {},
|
|
@@ -4104,6 +4061,10 @@ module.exports = app => app.component('list-json', {
|
|
|
4104
4061
|
expandTopLevel: {
|
|
4105
4062
|
type: Function,
|
|
4106
4063
|
default: null
|
|
4064
|
+
},
|
|
4065
|
+
references: {
|
|
4066
|
+
type: Object,
|
|
4067
|
+
default: () => ({})
|
|
4107
4068
|
}
|
|
4108
4069
|
},
|
|
4109
4070
|
computed: {
|
|
@@ -4242,6 +4203,24 @@ module.exports = app => app.component('list-json', {
|
|
|
4242
4203
|
},
|
|
4243
4204
|
hiddenChildrenTooltip() {
|
|
4244
4205
|
return this.hiddenChildrenLabel;
|
|
4206
|
+
},
|
|
4207
|
+
normalizedPath() {
|
|
4208
|
+
if (typeof this.path !== 'string') {
|
|
4209
|
+
return '';
|
|
4210
|
+
}
|
|
4211
|
+
return this.path
|
|
4212
|
+
.replace(/^root\.?/, '')
|
|
4213
|
+
.replace(/\[\d+\]/g, '')
|
|
4214
|
+
.replace(/^\./, '');
|
|
4215
|
+
},
|
|
4216
|
+
referenceModel() {
|
|
4217
|
+
if (!this.normalizedPath || !this.references) {
|
|
4218
|
+
return null;
|
|
4219
|
+
}
|
|
4220
|
+
return this.references[this.normalizedPath] || null;
|
|
4221
|
+
},
|
|
4222
|
+
shouldShowReferenceLink() {
|
|
4223
|
+
return Boolean(this.referenceModel) && typeof this.value === 'string';
|
|
4245
4224
|
}
|
|
4246
4225
|
},
|
|
4247
4226
|
methods: {
|
|
@@ -4266,6 +4245,12 @@ module.exports = app => app.component('list-json', {
|
|
|
4266
4245
|
if (this.isRoot && typeof this.expandTopLevel === 'function') {
|
|
4267
4246
|
this.expandTopLevel();
|
|
4268
4247
|
}
|
|
4248
|
+
},
|
|
4249
|
+
goToReference(id) {
|
|
4250
|
+
if (!this.referenceModel) {
|
|
4251
|
+
return;
|
|
4252
|
+
}
|
|
4253
|
+
this.$router.push({ path: `/model/${this.referenceModel}/document/${id}` });
|
|
4269
4254
|
}
|
|
4270
4255
|
}
|
|
4271
4256
|
}
|
|
@@ -4557,7 +4542,7 @@ module.exports = ".models {\n position: relative;\n display: flex;\n flex-dir
|
|
|
4557
4542
|
/***/ ((module) => {
|
|
4558
4543
|
|
|
4559
4544
|
"use strict";
|
|
4560
|
-
module.exports = "<div class=\"models flex\" style=\"height: calc(100vh - 55px); height: calc(100dvh - 55px)\">\n <div class=\"fixed top-[65px] cursor-pointer bg-gray-100 rounded-r-md z-10\" @click=\"hideSidebar = false\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"#5f6368\"><path d=\"M360-120v-720h80v720h-80Zm160-160v-400l200 200-200 200Z\"/></svg>\n </div>\n <aside class=\"bg-white border-r overflow-y-auto overflow-x-hidden h-full transition-all duration-300 ease-in-out z-20 w-0 lg:w-48 fixed lg:relative shrink-0\" :class=\"hideSidebar === true ? '!w-0' : hideSidebar === false ? '!w-48' : ''\">\n <div class=\"flex items-center border-b border-gray-100 w-48 overflow-x-hidden\">\n <div class=\"p-4 font-bold text-lg\">Models</div>\n <button\n @click=\"hideSidebar = true\"\n class=\"ml-auto mr-2 p-2 rounded hover:bg-gray-200 focus:outline-none\"\n aria-label=\"Close sidebar\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"currentColor\"><path d=\"M660-320v-320L500-480l160 160ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm120-80v-560H200v560h120Zm80 0h360v-560H400v560Zm-80 0H200h120Z\"/></svg>\n </button>\n </div>\n <nav class=\"flex flex-1 flex-col\">\n <ul role=\"list\" class=\"flex flex-1 flex-col gap-y-7\">\n <li>\n <ul role=\"list\">\n <li v-for=\"model in models\">\n <router-link\n :to=\"'/model/' + model\"\n class=\"block truncate rounded-md py-2 pr-2 pl-2 text-sm font-semibold text-gray-700\"\n :class=\"model === currentModel ? 'bg-ultramarine-100 font-bold' : 'hover:bg-ultramarine-100'\">\n {{model}}\n </router-link>\n </li>\n </ul>\n </li>\n </ul>\n <div v-if=\"models.length === 0 && status === 'loaded'\" class=\"p-2 bg-red-100\">\n No models found\n </div>\n </nav>\n </aside>\n <div class=\"documents\" ref=\"documentsList\">\n <div class=\"relative h-[42px] z-10\">\n <div class=\"documents-menu\">\n <div class=\"flex flex-row items-center w-full gap-2\">\n <form @submit.prevent=\"search\" class=\"relative flex-grow m-0\">\n <input ref=\"searchInput\" class=\"w-full font-mono rounded-md p-1 border border-gray-300 outline-gray-300 text-lg focus:ring-1 focus:ring-ultramarine-200 focus:ring-offset-0 focus:outline-none\" type=\"text\" placeholder=\"Filter\" v-model=\"searchText\" @click=\"initFilter\" @input=\"updateAutocomplete\" @keydown=\"handleKeyDown\" />\n <ul v-if=\"autocompleteSuggestions.length\" class=\"absolute z-[9999] bg-white border border-gray-300 rounded mt-1 w-full max-h-40 overflow-y-auto shadow\">\n <li v-for=\"(suggestion, index) in autocompleteSuggestions\" :key=\"suggestion\" class=\"px-2 py-1 cursor-pointer\" :class=\"{ 'bg-ultramarine-100': index === autocompleteIndex }\" @mousedown.prevent=\"applySuggestion(index)\">{{ suggestion }}</li>\n </ul>\n </form>\n <div>\n <span v-if=\"numDocuments == null\">Loading ...</span>\n <span v-else-if=\"typeof numDocuments === 'number'\">{{numDocuments === 1 ? numDocuments+ ' document' : numDocuments + ' documents'}}</span>\n </div>\n <button\n @click=\"shouldShowExportModal = true\"\n type=\"button\"\n v-show=\"!selectMultiple\"\n class=\"rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">\n Export\n </button>\n <button\n @click=\"stagingSelect\"\n type=\"button\"\n :class=\"{ 'bg-gray-500 ring-inset ring-2 ring-gray-300 hover:bg-gray-600': selectMultiple, 'bg-ultramarine-600 hover:bg-ultramarine-500' : !selectMultiple }\"\n class=\"rounded px-2 py-2 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\"\n >\n {{ selectMultiple ? 'Cancel' : 'Select' }}\n </button>\n <button\n v-show=\"selectMultiple\"\n @click=\"shouldShowUpdateMultipleModal=true;\"\n type=\"button\"\n class=\"rounded bg-green-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\"\n >\n Update\n </button>\n <button\n @click=\"shouldShowDeleteMultipleModal=true;\"\n type=\"button\"\n v-show=\"selectMultiple\"\n class=\"rounded bg-red-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500\"\n >\n Delete\n </button>\n <button\n @click=\"openIndexModal\"\n type=\"button\"\n v-show=\"!selectMultiple\"\n class=\"rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">\n Indexes\n </button>\n <button\n @click=\"shouldShowCreateModal = true;\"\n type=\"button\"\n v-show=\"!selectMultiple\"\n class=\"rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">\n Create\n </button>\n <button\n @click=\"openFieldSelection\"\n type=\"button\"\n v-show=\"!selectMultiple\"\n class=\"rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">\n Fields\n </button>\n <span class=\"isolate inline-flex rounded-md shadow-sm\">\n <button\n @click=\"setOutputType('table')\"\n type=\"button\"\n class=\"relative inline-flex items-center rounded-none rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10\"\n :class=\"outputType === 'table' ? 'bg-gray-200' : 'bg-white'\">\n <img class=\"h-5 w-5\" src=\"images/table.svg\">\n </button>\n <button\n @click=\"setOutputType('json')\"\n type=\"button\"\n class=\"relative -ml-px inline-flex items-center rounded-none rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10\"\n :class=\"outputType === 'json' ? 'bg-gray-200' : 'bg-white'\">\n <img class=\"h-5 w-5\" src=\"images/json.svg\">\n </button>\n </span>\n </div>\n </div>\n </div>\n <div class=\"documents-container relative\">\n <div v-if=\"error\">\n <div class=\"bg-red-100 border border-red-400 text-red-700 px-4 py-3 relative m-4 rounded-md\" role=\"alert\">\n <span class=\"block font-bold\">Error</span>\n <span class=\"block\">{{ error }}</span>\n </div>\n </div>\n <table v-else-if=\"outputType === 'table'\">\n <thead>\n <th v-for=\"path in filteredPaths\" @click=\"clickFilter(path.path)\" class=\"cursor-pointer\">\n {{path.path}}\n <span class=\"path-type\">\n ({{(path.instance || 'unknown')}})\n </span>\n <span class=\"sort-arrow\" @click=\"sortDocs(1, path.path)\">{{sortBy[path.path] == 1 ? 'X' : '↑'}}</span>\n <span class=\"sort-arrow\" @click=\"sortDocs(-1, path.path)\">{{sortBy[path.path] == -1 ? 'X' : '↓'}}</span>\n </th>\n </thead>\n <tbody>\n <tr v-for=\"document in documents\" @click=\"handleDocumentClick(document, $event)\" :key=\"document._id\">\n <td v-for=\"schemaPath in filteredPaths\" :class=\"{ 'bg-blue-200': selectedDocuments.some(x => x._id.toString() === document._id.toString()) }\">\n <component\n :is=\"getComponentForPath(schemaPath)\"\n :value=\"getValueForPath(document, schemaPath.path)\"\n :allude=\"getReferenceModel(schemaPath)\">\n </component>\n </td>\n </tr>\n </tbody>\n </table>\n <div v-else-if=\"outputType === 'json'\" class=\"flex flex-col space-y-6\">\n <div\n v-for=\"document in documents\"\n :key=\"document._id\"\n @click=\"handleDocumentContainerClick(document, $event)\"\n :class=\"[\n 'group relative transition-colors',\n selectedDocuments.some(x => x._id.toString() === document._id.toString()) ? 'bg-blue-200' : 'hover:bg-slate-100'\n ]\"\n >\n <button\n type=\"button\"\n class=\"absolute top-2 right-2 z-10 inline-flex items-center rounded bg-ultramarine-600 px-2 py-1 text-xs font-semibold text-white shadow-sm transition-opacity duration-150 opacity-0 group-hover:opacity-100 focus-visible:opacity-100 hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\"\n @click.stop=\"openDocument(document)\"\n >\n Open this Document\n </button>\n <list-json :value=\"filterDocument(document)\">\n </list-json>\n </div>\n </div>\n <div v-if=\"status === 'loading'\" class=\"loader\">\n <img src=\"images/loader.gif\">\n </div>\n </div>\n </div>\n <modal v-if=\"shouldShowExportModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowExportModal = false\">×</div>\n <export-query-results\n :schemaPaths=\"schemaPaths\"\n :search-text=\"searchText\"\n :currentModel=\"currentModel\"\n @done=\"shouldShowExportModal = false\">\n </export-query-results>\n </template>\n </modal>\n <modal v-if=\"shouldShowIndexModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowIndexModal = false\">×</div>\n <div class=\"text-xl font-bold mb-2\">Indexes</div>\n <div v-for=\"index in mongoDBIndexes\" class=\"w-full flex items-center\">\n <div class=\"grow shrink text-left flex justify-between items-center\" v-if=\"index.name != '_id_'\">\n <div>\n <div class=\"font-bold\">{{ index.name }}</div>\n <div class=\"text-sm font-mono\">{{ JSON.stringify(index.key) }}</div>\n </div>\n <div>\n <async-button\n type=\"button\"\n @click=\"dropIndex(index.name)\"\n class=\"rounded-md bg-valencia-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-valencia-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600 disabled:bg-gray-400 disabled:cursor-not-allowed\">\n Drop\n </async-button>\n </div>\n </div>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowFieldModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowFieldModal = false; selectedPaths = [...filteredPaths];\">×</div>\n <div v-for=\"(path, index) in schemaPaths\" :key=\"index\" class=\"w-5 flex items-center\">\n <input class=\"mt-0 h-4 w-4 rounded border-gray-300 text-sky-600 focus:ring-sky-600 accent-sky-600\" type=\"checkbox\" :id=\"'path.path'+index\" @change=\"addOrRemove(path)\" :value=\"path.path\" :checked=\"isSelected(path.path)\" />\n <div class=\"ml-2 text-gray-700 grow shrink text-left\">\n <label :for=\"'path.path' + index\">{{path.path}}</label>\n </div>\n </div>\n <div class=\"mt-4 flex gap-2\">\n <button type=\"button\" @click=\"filterDocuments()\" class=\"rounded-md bg-ultramarine-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600\">Filter Selection</button>\n <button type=\"button\" @click=\"selectAll()\" class=\"rounded-md bg-forest-green-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\">Select All</button>\n <button type=\"button\" @click=\"deselectAll()\" class=\"rounded-md bg-valencia-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-valencia-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600\">Deselect All</button>\n <button type=\"button\" @click=\"resetDocuments()\" class=\"rounded-md bg-gray-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\" >Cancel</button>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowCreateModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowCreateModal = false;\">×</div>\n <create-document :currentModel=\"currentModel\" :paths=\"schemaPaths\" @close=\"closeCreationModal\"></create-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowUpdateMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowUpdateMultipleModal = false;\">×</div>\n <update-document :currentModel=\"currentModel\" :document=\"selectedDocuments\" :multiple=\"true\" @update=\"updateDocuments\" @close=\"shouldShowUpdateMultipleModal=false;\"></update-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowDeleteMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowDeleteMultipleModal = false;\">×</div>\n <h2>Are you sure you want to delete {{selectedDocuments.length}} documents?</h2>\n <div>\n <list-json :value=\"selectedDocuments\"></list-json>\n </div>\n <div class=\"flex gap-4\">\n <async-button @click=\"deleteDocuments\" class=\"rounded bg-red-500 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600\">\n Confirm\n </async-button>\n <button @click=\"shouldShowDeleteMultipleModal = false;\" class=\"rounded bg-gray-400 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500\">\n Cancel\n </button>\n </div>\n </template>\n </modal>\n</div>\n";
|
|
4545
|
+
module.exports = "<div class=\"models flex\" style=\"height: calc(100vh - 55px); height: calc(100dvh - 55px)\">\n <div class=\"fixed top-[65px] cursor-pointer bg-gray-100 rounded-r-md z-10\" @click=\"hideSidebar = false\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"#5f6368\"><path d=\"M360-120v-720h80v720h-80Zm160-160v-400l200 200-200 200Z\"/></svg>\n </div>\n <aside class=\"bg-white border-r overflow-y-auto overflow-x-hidden h-full transition-all duration-300 ease-in-out z-20 w-0 lg:w-48 fixed lg:relative shrink-0\" :class=\"hideSidebar === true ? '!w-0' : hideSidebar === false ? '!w-48' : ''\">\n <div class=\"flex items-center border-b border-gray-100 w-48 overflow-x-hidden\">\n <div class=\"p-4 font-bold text-lg\">Models</div>\n <button\n @click=\"hideSidebar = true\"\n class=\"ml-auto mr-2 p-2 rounded hover:bg-gray-200 focus:outline-none\"\n aria-label=\"Close sidebar\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"currentColor\"><path d=\"M660-320v-320L500-480l160 160ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm120-80v-560H200v560h120Zm80 0h360v-560H400v560Zm-80 0H200h120Z\"/></svg>\n </button>\n </div>\n <nav class=\"flex flex-1 flex-col\">\n <ul role=\"list\" class=\"flex flex-1 flex-col gap-y-7\">\n <li>\n <ul role=\"list\">\n <li v-for=\"model in models\">\n <router-link\n :to=\"'/model/' + model\"\n class=\"block truncate rounded-md py-2 pr-2 pl-2 text-sm font-semibold text-gray-700\"\n :class=\"model === currentModel ? 'bg-ultramarine-100 font-bold' : 'hover:bg-ultramarine-100'\">\n {{model}}\n </router-link>\n </li>\n </ul>\n </li>\n </ul>\n <div v-if=\"models.length === 0 && status === 'loaded'\" class=\"p-2 bg-red-100\">\n No models found\n </div>\n </nav>\n </aside>\n <div class=\"documents\" ref=\"documentsList\">\n <div class=\"relative h-[42px] z-10\">\n <div class=\"documents-menu\">\n <div class=\"flex flex-row items-center w-full gap-2\">\n <form @submit.prevent=\"search\" class=\"relative flex-grow m-0\">\n <input ref=\"searchInput\" class=\"w-full font-mono rounded-md p-1 border border-gray-300 outline-gray-300 text-lg focus:ring-1 focus:ring-ultramarine-200 focus:ring-offset-0 focus:outline-none\" type=\"text\" placeholder=\"Filter\" v-model=\"searchText\" @click=\"initFilter\" @input=\"updateAutocomplete\" @keydown=\"handleKeyDown\" />\n <ul v-if=\"autocompleteSuggestions.length\" class=\"absolute z-[9999] bg-white border border-gray-300 rounded mt-1 w-full max-h-40 overflow-y-auto shadow\">\n <li v-for=\"(suggestion, index) in autocompleteSuggestions\" :key=\"suggestion\" class=\"px-2 py-1 cursor-pointer\" :class=\"{ 'bg-ultramarine-100': index === autocompleteIndex }\" @mousedown.prevent=\"applySuggestion(index)\">{{ suggestion }}</li>\n </ul>\n </form>\n <div>\n <span v-if=\"numDocuments == null\">Loading ...</span>\n <span v-else-if=\"typeof numDocuments === 'number'\">{{numDocuments === 1 ? numDocuments+ ' document' : numDocuments + ' documents'}}</span>\n </div>\n <button\n @click=\"shouldShowExportModal = true\"\n type=\"button\"\n v-show=\"!selectMultiple\"\n class=\"rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">\n Export\n </button>\n <button\n @click=\"stagingSelect\"\n type=\"button\"\n :class=\"{ 'bg-gray-500 ring-inset ring-2 ring-gray-300 hover:bg-gray-600': selectMultiple, 'bg-ultramarine-600 hover:bg-ultramarine-500' : !selectMultiple }\"\n class=\"rounded px-2 py-2 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\"\n >\n {{ selectMultiple ? 'Cancel' : 'Select' }}\n </button>\n <button\n v-show=\"selectMultiple\"\n @click=\"shouldShowUpdateMultipleModal=true;\"\n type=\"button\"\n class=\"rounded bg-green-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\"\n >\n Update\n </button>\n <button\n @click=\"shouldShowDeleteMultipleModal=true;\"\n type=\"button\"\n v-show=\"selectMultiple\"\n class=\"rounded bg-red-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500\"\n >\n Delete\n </button>\n <button\n @click=\"openIndexModal\"\n type=\"button\"\n v-show=\"!selectMultiple\"\n class=\"rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">\n Indexes\n </button>\n <button\n @click=\"shouldShowCreateModal = true;\"\n type=\"button\"\n v-show=\"!selectMultiple\"\n class=\"rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">\n Create\n </button>\n <button\n @click=\"openFieldSelection\"\n type=\"button\"\n v-show=\"!selectMultiple\"\n class=\"rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">\n Fields\n </button>\n <span class=\"isolate inline-flex rounded-md shadow-sm\">\n <button\n @click=\"setOutputType('table')\"\n type=\"button\"\n class=\"relative inline-flex items-center rounded-none rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10\"\n :class=\"outputType === 'table' ? 'bg-gray-200' : 'bg-white'\">\n <img class=\"h-5 w-5\" src=\"images/table.svg\">\n </button>\n <button\n @click=\"setOutputType('json')\"\n type=\"button\"\n class=\"relative -ml-px inline-flex items-center rounded-none rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10\"\n :class=\"outputType === 'json' ? 'bg-gray-200' : 'bg-white'\">\n <img class=\"h-5 w-5\" src=\"images/json.svg\">\n </button>\n </span>\n </div>\n </div>\n </div>\n <div class=\"documents-container relative\">\n <div v-if=\"error\">\n <div class=\"bg-red-100 border border-red-400 text-red-700 px-4 py-3 relative m-4 rounded-md\" role=\"alert\">\n <span class=\"block font-bold\">Error</span>\n <span class=\"block\">{{ error }}</span>\n </div>\n </div>\n <table v-else-if=\"outputType === 'table'\">\n <thead>\n <th v-for=\"path in filteredPaths\" @click=\"clickFilter(path.path)\" class=\"cursor-pointer\">\n {{path.path}}\n <span class=\"path-type\">\n ({{(path.instance || 'unknown')}})\n </span>\n <span class=\"sort-arrow\" @click=\"sortDocs(1, path.path)\">{{sortBy[path.path] == 1 ? 'X' : '↑'}}</span>\n <span class=\"sort-arrow\" @click=\"sortDocs(-1, path.path)\">{{sortBy[path.path] == -1 ? 'X' : '↓'}}</span>\n </th>\n </thead>\n <tbody>\n <tr v-for=\"document in documents\" @click=\"handleDocumentClick(document, $event)\" :key=\"document._id\">\n <td v-for=\"schemaPath in filteredPaths\" :class=\"{ 'bg-blue-200': selectedDocuments.some(x => x._id.toString() === document._id.toString()) }\">\n <component\n :is=\"getComponentForPath(schemaPath)\"\n :value=\"getValueForPath(document, schemaPath.path)\"\n :allude=\"getReferenceModel(schemaPath)\">\n </component>\n </td>\n </tr>\n </tbody>\n </table>\n <div v-else-if=\"outputType === 'json'\" class=\"flex flex-col space-y-6\">\n <div\n v-for=\"document in documents\"\n :key=\"document._id\"\n @click=\"handleDocumentContainerClick(document, $event)\"\n :class=\"[\n 'group relative transition-colors',\n selectedDocuments.some(x => x._id.toString() === document._id.toString()) ? 'bg-blue-200' : 'hover:bg-slate-100'\n ]\"\n >\n <button\n type=\"button\"\n class=\"absolute top-2 right-2 z-10 inline-flex items-center rounded bg-ultramarine-600 px-2 py-1 text-xs font-semibold text-white shadow-sm transition-opacity duration-150 opacity-0 group-hover:opacity-100 focus-visible:opacity-100 hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\"\n @click.stop=\"openDocument(document)\"\n >\n Open this Document\n </button>\n <list-json :value=\"filterDocument(document)\" :references=\"referenceMap\">\n </list-json>\n </div>\n </div>\n <div v-if=\"status === 'loading'\" class=\"loader\">\n <img src=\"images/loader.gif\">\n </div>\n </div>\n </div>\n <modal v-if=\"shouldShowExportModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowExportModal = false\">×</div>\n <export-query-results\n :schemaPaths=\"schemaPaths\"\n :search-text=\"searchText\"\n :currentModel=\"currentModel\"\n @done=\"shouldShowExportModal = false\">\n </export-query-results>\n </template>\n </modal>\n <modal v-if=\"shouldShowIndexModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowIndexModal = false\">×</div>\n <div class=\"text-xl font-bold mb-2\">Indexes</div>\n <div v-for=\"index in mongoDBIndexes\" class=\"w-full flex items-center\">\n <div class=\"grow shrink text-left flex justify-between items-center\" v-if=\"index.name != '_id_'\">\n <div>\n <div class=\"font-bold\">{{ index.name }}</div>\n <div class=\"text-sm font-mono\">{{ JSON.stringify(index.key) }}</div>\n </div>\n <div>\n <async-button\n type=\"button\"\n @click=\"dropIndex(index.name)\"\n class=\"rounded-md bg-valencia-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-valencia-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600 disabled:bg-gray-400 disabled:cursor-not-allowed\">\n Drop\n </async-button>\n </div>\n </div>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowFieldModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowFieldModal = false; selectedPaths = [...filteredPaths];\">×</div>\n <div v-for=\"(path, index) in schemaPaths\" :key=\"index\" class=\"w-5 flex items-center\">\n <input class=\"mt-0 h-4 w-4 rounded border-gray-300 text-sky-600 focus:ring-sky-600 accent-sky-600\" type=\"checkbox\" :id=\"'path.path'+index\" @change=\"addOrRemove(path)\" :value=\"path.path\" :checked=\"isSelected(path.path)\" />\n <div class=\"ml-2 text-gray-700 grow shrink text-left\">\n <label :for=\"'path.path' + index\">{{path.path}}</label>\n </div>\n </div>\n <div class=\"mt-4 flex gap-2\">\n <button type=\"button\" @click=\"filterDocuments()\" class=\"rounded-md bg-ultramarine-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600\">Filter Selection</button>\n <button type=\"button\" @click=\"selectAll()\" class=\"rounded-md bg-forest-green-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\">Select All</button>\n <button type=\"button\" @click=\"deselectAll()\" class=\"rounded-md bg-valencia-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-valencia-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600\">Deselect All</button>\n <button type=\"button\" @click=\"resetDocuments()\" class=\"rounded-md bg-gray-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\" >Cancel</button>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowCreateModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowCreateModal = false;\">×</div>\n <create-document :currentModel=\"currentModel\" :paths=\"schemaPaths\" @close=\"closeCreationModal\"></create-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowUpdateMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowUpdateMultipleModal = false;\">×</div>\n <update-document :currentModel=\"currentModel\" :document=\"selectedDocuments\" :multiple=\"true\" @update=\"updateDocuments\" @close=\"shouldShowUpdateMultipleModal=false;\"></update-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowDeleteMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowDeleteMultipleModal = false;\">×</div>\n <h2>Are you sure you want to delete {{selectedDocuments.length}} documents?</h2>\n <div>\n <list-json :value=\"selectedDocuments\"></list-json>\n </div>\n <div class=\"flex gap-4\">\n <async-button @click=\"deleteDocuments\" class=\"rounded bg-red-500 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600\">\n Confirm\n </async-button>\n <button @click=\"shouldShowDeleteMultipleModal = false;\" class=\"rounded bg-gray-400 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500\">\n Cancel\n </button>\n </div>\n </template>\n </modal>\n</div>\n";
|
|
4561
4546
|
|
|
4562
4547
|
/***/ }),
|
|
4563
4548
|
|
|
@@ -4678,6 +4663,17 @@ module.exports = app => app.component('models', {
|
|
|
4678
4663
|
|
|
4679
4664
|
await this.initSearchFromUrl();
|
|
4680
4665
|
},
|
|
4666
|
+
computed: {
|
|
4667
|
+
referenceMap() {
|
|
4668
|
+
const map = {};
|
|
4669
|
+
for (const path of this.filteredPaths) {
|
|
4670
|
+
if (path?.ref) {
|
|
4671
|
+
map[path.path] = path.ref;
|
|
4672
|
+
}
|
|
4673
|
+
}
|
|
4674
|
+
return map;
|
|
4675
|
+
}
|
|
4676
|
+
},
|
|
4681
4677
|
methods: {
|
|
4682
4678
|
buildAutocompleteTrie() {
|
|
4683
4679
|
this.autocompleteTrie = new Trie();
|
|
@@ -4908,9 +4904,10 @@ module.exports = app => app.component('models', {
|
|
|
4908
4904
|
},
|
|
4909
4905
|
filterDocument(doc) {
|
|
4910
4906
|
const filteredDoc = {};
|
|
4911
|
-
console.log(doc, this.filteredPaths);
|
|
4912
4907
|
for (let i = 0; i < this.filteredPaths.length; i++) {
|
|
4913
|
-
|
|
4908
|
+
const path = this.filteredPaths[i].path;
|
|
4909
|
+
const value = mpath.get(path, doc);
|
|
4910
|
+
mpath.set(path, value, filteredDoc);
|
|
4914
4911
|
}
|
|
4915
4912
|
return filteredDoc;
|
|
4916
4913
|
},
|
|
@@ -16609,7 +16606,7 @@ module.exports = function stringToParts(str) {
|
|
|
16609
16606
|
/***/ ((module) => {
|
|
16610
16607
|
|
|
16611
16608
|
"use strict";
|
|
16612
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.1.
|
|
16609
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.1.6","description":"A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.","homepage":"https://studio.mongoosejs.io/","repository":{"type":"git","url":"https://github.com/mongoosejs/studio"},"license":"Apache-2.0","dependencies":{"archetype":"0.13.1","csv-stringify":"6.3.0","ejson":"^2.2.3","extrovert":"^0.2.0","marked":"15.0.12","node-inspect-extracted":"3.x","tailwindcss":"3.4.0","vanillatoasts":"^1.6.0","vue":"3.x","webpack":"5.x"},"peerDependencies":{"bson":"^5.5.1 || 6.x","express":"4.x","mongoose":"7.x || 8.x || ^9.0.0-0"},"devDependencies":{"@masteringjs/eslint-config":"0.1.1","axios":"1.2.2","dedent":"^1.6.0","eslint":"9.30.0","express":"4.x","mocha":"10.2.0","mongoose":"9.x"},"scripts":{"lint":"eslint .","tailwind":"tailwindcss -o ./frontend/public/tw.css","tailwind:watch":"tailwindcss -o ./frontend/public/tw.css --watch","test":"mocha test/*.test.js"}}');
|
|
16613
16610
|
|
|
16614
16611
|
/***/ })
|
|
16615
16612
|
|
package/frontend/public/tw.css
CHANGED
|
@@ -2041,6 +2041,11 @@ video {
|
|
|
2041
2041
|
color: rgb(2 132 199 / var(--tw-text-opacity));
|
|
2042
2042
|
}
|
|
2043
2043
|
|
|
2044
|
+
.text-sky-700 {
|
|
2045
|
+
--tw-text-opacity: 1;
|
|
2046
|
+
color: rgb(3 105 161 / var(--tw-text-opacity));
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2044
2049
|
.text-sky-800 {
|
|
2045
2050
|
--tw-text-opacity: 1;
|
|
2046
2051
|
color: rgb(7 89 133 / var(--tw-text-opacity));
|
|
@@ -2086,6 +2091,18 @@ video {
|
|
|
2086
2091
|
color: rgb(255 255 255 / var(--tw-text-opacity));
|
|
2087
2092
|
}
|
|
2088
2093
|
|
|
2094
|
+
.underline {
|
|
2095
|
+
text-decoration-line: underline;
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
.decoration-dotted {
|
|
2099
|
+
text-decoration-style: dotted;
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
.underline-offset-2 {
|
|
2103
|
+
text-underline-offset: 2px;
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2089
2106
|
.accent-sky-600 {
|
|
2090
2107
|
accent-color: #0284c7;
|
|
2091
2108
|
}
|
|
@@ -2469,6 +2486,10 @@ video {
|
|
|
2469
2486
|
border-color: transparent;
|
|
2470
2487
|
}
|
|
2471
2488
|
|
|
2489
|
+
.focus\:opacity-100:focus {
|
|
2490
|
+
opacity: 1;
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2472
2493
|
.focus\:outline-none:focus {
|
|
2473
2494
|
outline: 2px solid transparent;
|
|
2474
2495
|
outline-offset: 2px;
|
|
@@ -44,6 +44,25 @@ module.exports = app => app.component('dashboard', {
|
|
|
44
44
|
} finally {
|
|
45
45
|
this.status = 'loaded';
|
|
46
46
|
}
|
|
47
|
+
},
|
|
48
|
+
shouldEvaluateDashboard() {
|
|
49
|
+
if (this.dashboardResults.length === 0) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const finishedEvaluatingAt = this.dashboardResults[0].finishedEvaluatingAt;
|
|
54
|
+
if (!finishedEvaluatingAt) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const sixHoursAgo = Date.now() - 6 * 60 * 60 * 1000;
|
|
59
|
+
const finishedAt = new Date(finishedEvaluatingAt).getTime();
|
|
60
|
+
|
|
61
|
+
if (Number.isNaN(finishedAt)) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return finishedAt < sixHoursAgo;
|
|
47
66
|
}
|
|
48
67
|
},
|
|
49
68
|
computed: {
|
|
@@ -62,6 +81,10 @@ module.exports = app => app.component('dashboard', {
|
|
|
62
81
|
this.title = this.dashboard.title;
|
|
63
82
|
this.description = this.dashboard.description ?? '';
|
|
64
83
|
this.dashboardResults = dashboardResults;
|
|
84
|
+
if (this.shouldEvaluateDashboard()) {
|
|
85
|
+
await this.evaluateDashboard();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
65
88
|
this.status = 'loaded';
|
|
66
89
|
}
|
|
67
90
|
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<div>
|
|
2
|
+
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
|
|
3
|
+
<button
|
|
4
|
+
v-if="showToggle"
|
|
5
|
+
type="button"
|
|
6
|
+
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"
|
|
7
|
+
@click.stop="handleToggle"
|
|
8
|
+
>
|
|
9
|
+
{{ isCollapsedNode ? '+' : '-' }}
|
|
10
|
+
</button>
|
|
11
|
+
<span v-else class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible flex-shrink-0"></span>
|
|
12
|
+
<template v-if="hasKey">
|
|
13
|
+
<span class="text-blue-600">"{{ nodeKey }}"</span><span>: </span>
|
|
14
|
+
</template>
|
|
15
|
+
<template v-if="isComplex">
|
|
16
|
+
<template v-if="hasChildren">
|
|
17
|
+
<span>{{ openingBracket }}</span>
|
|
18
|
+
<span v-if="isCollapsedNode" class="mx-1">…</span>
|
|
19
|
+
<span v-if="isCollapsedNode">{{ closingBracket }}{{ comma }}</span>
|
|
20
|
+
</template>
|
|
21
|
+
<template v-else>
|
|
22
|
+
<span>{{ openingBracket }}{{ closingBracket }}{{ comma }}</span>
|
|
23
|
+
</template>
|
|
24
|
+
</template>
|
|
25
|
+
<template v-else>
|
|
26
|
+
<!--
|
|
27
|
+
If value is a string and overflows its container (i.e. goes over one line), show an ellipsis.
|
|
28
|
+
This is done via CSS ellipsis strategy.
|
|
29
|
+
-->
|
|
30
|
+
<span
|
|
31
|
+
v-if="shouldShowReferenceLink"
|
|
32
|
+
class="inline-flex items-baseline group"
|
|
33
|
+
>
|
|
34
|
+
<span
|
|
35
|
+
:class="[...valueClasses, 'underline', 'decoration-dotted', 'underline-offset-2']"
|
|
36
|
+
:style="typeof value === 'string'
|
|
37
|
+
? {
|
|
38
|
+
display: 'inline-block',
|
|
39
|
+
maxWidth: '100%',
|
|
40
|
+
overflow: 'hidden',
|
|
41
|
+
textOverflow: 'ellipsis',
|
|
42
|
+
whiteSpace: 'nowrap',
|
|
43
|
+
verticalAlign: 'bottom'
|
|
44
|
+
}
|
|
45
|
+
: {}"
|
|
46
|
+
:title="typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined"
|
|
47
|
+
>
|
|
48
|
+
{{ formattedValue }}
|
|
49
|
+
</span>
|
|
50
|
+
<span>
|
|
51
|
+
{{ comma }}
|
|
52
|
+
</span>
|
|
53
|
+
<a
|
|
54
|
+
href="#"
|
|
55
|
+
class="ml-1 text-sm text-sky-700 opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity"
|
|
56
|
+
@click.stop.prevent="goToReference(value)"
|
|
57
|
+
>
|
|
58
|
+
View Document
|
|
59
|
+
</a>
|
|
60
|
+
</span>
|
|
61
|
+
<span
|
|
62
|
+
v-else
|
|
63
|
+
:class="valueClasses"
|
|
64
|
+
:style="typeof value === 'string'
|
|
65
|
+
? {
|
|
66
|
+
display: 'inline-block',
|
|
67
|
+
maxWidth: '100%',
|
|
68
|
+
overflow: 'hidden',
|
|
69
|
+
textOverflow: 'ellipsis',
|
|
70
|
+
whiteSpace: 'nowrap',
|
|
71
|
+
verticalAlign: 'bottom'
|
|
72
|
+
}
|
|
73
|
+
: {}"
|
|
74
|
+
:title="typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined"
|
|
75
|
+
>
|
|
76
|
+
{{ formattedValue }}{{ comma }}
|
|
77
|
+
</span>
|
|
78
|
+
</template>
|
|
79
|
+
</div>
|
|
80
|
+
<template v-if="isComplex && hasChildren && !isCollapsedNode">
|
|
81
|
+
<json-node
|
|
82
|
+
v-for="child in children"
|
|
83
|
+
:key="child.path"
|
|
84
|
+
:node-key="child.displayKey"
|
|
85
|
+
:value="child.value"
|
|
86
|
+
:level="level + 1"
|
|
87
|
+
:is-last="child.isLast"
|
|
88
|
+
:path="child.path"
|
|
89
|
+
:toggle-collapse="toggleCollapse"
|
|
90
|
+
:is-collapsed="isCollapsed"
|
|
91
|
+
:create-child-path="createChildPath"
|
|
92
|
+
:indent-size="indentSize"
|
|
93
|
+
:max-top-level-fields="maxTopLevelFields"
|
|
94
|
+
:top-level-expanded="topLevelExpanded"
|
|
95
|
+
:expand-top-level="expandTopLevel"
|
|
96
|
+
:references="references"
|
|
97
|
+
></json-node>
|
|
98
|
+
<div
|
|
99
|
+
v-if="hasHiddenRootChildren"
|
|
100
|
+
class="flex items-baseline whitespace-pre"
|
|
101
|
+
:style="indentStyle"
|
|
102
|
+
>
|
|
103
|
+
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
|
|
104
|
+
<button
|
|
105
|
+
type="button"
|
|
106
|
+
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"
|
|
107
|
+
:title="hiddenChildrenTooltip"
|
|
108
|
+
@click.stop="handleExpandTopLevel"
|
|
109
|
+
>
|
|
110
|
+
<span aria-hidden="true">{{hiddenChildrenLabel}}…</span>
|
|
111
|
+
</button>
|
|
112
|
+
</div>
|
|
113
|
+
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
|
|
114
|
+
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
|
|
115
|
+
<span>{{ closingBracket }}{{ comma }}</span>
|
|
116
|
+
</div>
|
|
117
|
+
</template>
|
|
118
|
+
</div>
|
|
@@ -2,97 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
const template = require('./list-json.html');
|
|
4
4
|
|
|
5
|
-
const JsonNodeTemplate =
|
|
6
|
-
<div>
|
|
7
|
-
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
|
|
8
|
-
<button
|
|
9
|
-
v-if="showToggle"
|
|
10
|
-
type="button"
|
|
11
|
-
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"
|
|
12
|
-
@click.stop="handleToggle"
|
|
13
|
-
>
|
|
14
|
-
{{ isCollapsedNode ? '+' : '-' }}
|
|
15
|
-
</button>
|
|
16
|
-
<span v-else class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible flex-shrink-0"></span>
|
|
17
|
-
<template v-if="hasKey">
|
|
18
|
-
<span class="text-blue-600">"{{ nodeKey }}"</span><span>: </span>
|
|
19
|
-
</template>
|
|
20
|
-
<template v-if="isComplex">
|
|
21
|
-
<template v-if="hasChildren">
|
|
22
|
-
<span>{{ openingBracket }}</span>
|
|
23
|
-
<span v-if="isCollapsedNode" class="mx-1">…</span>
|
|
24
|
-
<span v-if="isCollapsedNode">{{ closingBracket }}{{ comma }}</span>
|
|
25
|
-
</template>
|
|
26
|
-
<template v-else>
|
|
27
|
-
<span>{{ openingBracket }}{{ closingBracket }}{{ comma }}</span>
|
|
28
|
-
</template>
|
|
29
|
-
</template>
|
|
30
|
-
<template v-else>
|
|
31
|
-
<!--
|
|
32
|
-
If value is a string and overflows its container (i.e. goes over one line), show an ellipsis.
|
|
33
|
-
This is done via CSS ellipsis strategy.
|
|
34
|
-
-->
|
|
35
|
-
<span
|
|
36
|
-
:class="valueClasses"
|
|
37
|
-
:style="typeof value === 'string'
|
|
38
|
-
? {
|
|
39
|
-
display: 'inline-block',
|
|
40
|
-
maxWidth: '100%',
|
|
41
|
-
overflow: 'hidden',
|
|
42
|
-
textOverflow: 'ellipsis',
|
|
43
|
-
whiteSpace: 'nowrap',
|
|
44
|
-
verticalAlign: 'bottom'
|
|
45
|
-
}
|
|
46
|
-
: {}"
|
|
47
|
-
:title="typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined"
|
|
48
|
-
>
|
|
49
|
-
{{ formattedValue }}{{ comma }}
|
|
50
|
-
</span>
|
|
51
|
-
</template>
|
|
52
|
-
</div>
|
|
53
|
-
<template v-if="isComplex && hasChildren && !isCollapsedNode">
|
|
54
|
-
<json-node
|
|
55
|
-
v-for="child in children"
|
|
56
|
-
:key="child.path"
|
|
57
|
-
:node-key="child.displayKey"
|
|
58
|
-
:value="child.value"
|
|
59
|
-
:level="level + 1"
|
|
60
|
-
:is-last="child.isLast"
|
|
61
|
-
:path="child.path"
|
|
62
|
-
:toggle-collapse="toggleCollapse"
|
|
63
|
-
:is-collapsed="isCollapsed"
|
|
64
|
-
:create-child-path="createChildPath"
|
|
65
|
-
:indent-size="indentSize"
|
|
66
|
-
:max-top-level-fields="maxTopLevelFields"
|
|
67
|
-
:top-level-expanded="topLevelExpanded"
|
|
68
|
-
:expand-top-level="expandTopLevel"
|
|
69
|
-
></json-node>
|
|
70
|
-
<div
|
|
71
|
-
v-if="hasHiddenRootChildren"
|
|
72
|
-
class="flex items-baseline whitespace-pre"
|
|
73
|
-
:style="indentStyle"
|
|
74
|
-
>
|
|
75
|
-
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
|
|
76
|
-
<button
|
|
77
|
-
type="button"
|
|
78
|
-
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"
|
|
79
|
-
:title="hiddenChildrenTooltip"
|
|
80
|
-
@click.stop="handleExpandTopLevel"
|
|
81
|
-
>
|
|
82
|
-
<span aria-hidden="true">{{hiddenChildrenLabel}}…</span>
|
|
83
|
-
</button>
|
|
84
|
-
</div>
|
|
85
|
-
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
|
|
86
|
-
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
|
|
87
|
-
<span>{{ closingBracket }}{{ comma }}</span>
|
|
88
|
-
</div>
|
|
89
|
-
</template>
|
|
90
|
-
</div>
|
|
91
|
-
`;
|
|
5
|
+
const JsonNodeTemplate = require('./json-node.html');
|
|
92
6
|
|
|
93
7
|
module.exports = app => app.component('list-json', {
|
|
94
8
|
template: template,
|
|
95
|
-
props:
|
|
9
|
+
props: {
|
|
10
|
+
value: {
|
|
11
|
+
required: true
|
|
12
|
+
},
|
|
13
|
+
references: {
|
|
14
|
+
type: Object,
|
|
15
|
+
default: () => ({})
|
|
16
|
+
}
|
|
17
|
+
},
|
|
96
18
|
data() {
|
|
97
19
|
return {
|
|
98
20
|
collapsedMap: {},
|
|
@@ -196,6 +118,10 @@ module.exports = app => app.component('list-json', {
|
|
|
196
118
|
expandTopLevel: {
|
|
197
119
|
type: Function,
|
|
198
120
|
default: null
|
|
121
|
+
},
|
|
122
|
+
references: {
|
|
123
|
+
type: Object,
|
|
124
|
+
default: () => ({})
|
|
199
125
|
}
|
|
200
126
|
},
|
|
201
127
|
computed: {
|
|
@@ -334,6 +260,24 @@ module.exports = app => app.component('list-json', {
|
|
|
334
260
|
},
|
|
335
261
|
hiddenChildrenTooltip() {
|
|
336
262
|
return this.hiddenChildrenLabel;
|
|
263
|
+
},
|
|
264
|
+
normalizedPath() {
|
|
265
|
+
if (typeof this.path !== 'string') {
|
|
266
|
+
return '';
|
|
267
|
+
}
|
|
268
|
+
return this.path
|
|
269
|
+
.replace(/^root\.?/, '')
|
|
270
|
+
.replace(/\[\d+\]/g, '')
|
|
271
|
+
.replace(/^\./, '');
|
|
272
|
+
},
|
|
273
|
+
referenceModel() {
|
|
274
|
+
if (!this.normalizedPath || !this.references) {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
return this.references[this.normalizedPath] || null;
|
|
278
|
+
},
|
|
279
|
+
shouldShowReferenceLink() {
|
|
280
|
+
return Boolean(this.referenceModel) && typeof this.value === 'string';
|
|
337
281
|
}
|
|
338
282
|
},
|
|
339
283
|
methods: {
|
|
@@ -358,6 +302,12 @@ module.exports = app => app.component('list-json', {
|
|
|
358
302
|
if (this.isRoot && typeof this.expandTopLevel === 'function') {
|
|
359
303
|
this.expandTopLevel();
|
|
360
304
|
}
|
|
305
|
+
},
|
|
306
|
+
goToReference(id) {
|
|
307
|
+
if (!this.referenceModel) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
this.$router.push({ path: `/model/${this.referenceModel}/document/${id}` });
|
|
361
311
|
}
|
|
362
312
|
}
|
|
363
313
|
}
|
|
@@ -108,6 +108,17 @@ module.exports = app => app.component('models', {
|
|
|
108
108
|
|
|
109
109
|
await this.initSearchFromUrl();
|
|
110
110
|
},
|
|
111
|
+
computed: {
|
|
112
|
+
referenceMap() {
|
|
113
|
+
const map = {};
|
|
114
|
+
for (const path of this.filteredPaths) {
|
|
115
|
+
if (path?.ref) {
|
|
116
|
+
map[path.path] = path.ref;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return map;
|
|
120
|
+
}
|
|
121
|
+
},
|
|
111
122
|
methods: {
|
|
112
123
|
buildAutocompleteTrie() {
|
|
113
124
|
this.autocompleteTrie = new Trie();
|
|
@@ -338,9 +349,10 @@ module.exports = app => app.component('models', {
|
|
|
338
349
|
},
|
|
339
350
|
filterDocument(doc) {
|
|
340
351
|
const filteredDoc = {};
|
|
341
|
-
console.log(doc, this.filteredPaths);
|
|
342
352
|
for (let i = 0; i < this.filteredPaths.length; i++) {
|
|
343
|
-
|
|
353
|
+
const path = this.filteredPaths[i].path;
|
|
354
|
+
const value = mpath.get(path, doc);
|
|
355
|
+
mpath.set(path, value, filteredDoc);
|
|
344
356
|
}
|
|
345
357
|
return filteredDoc;
|
|
346
358
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mongoosejs/studio",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.",
|
|
5
5
|
"homepage": "https://studio.mongoosejs.io/",
|
|
6
6
|
"repository": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"archetype": "0.13.1",
|
|
13
13
|
"csv-stringify": "6.3.0",
|
|
14
14
|
"ejson": "^2.2.3",
|
|
15
|
-
"extrovert": "^0.
|
|
15
|
+
"extrovert": "^0.2.0",
|
|
16
16
|
"marked": "15.0.12",
|
|
17
17
|
"node-inspect-extracted": "3.x",
|
|
18
18
|
"tailwindcss": "3.4.0",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"bson": "^5.5.1 || 6.x",
|
|
25
25
|
"express": "4.x",
|
|
26
|
-
"mongoose": "7.x || 8.x"
|
|
26
|
+
"mongoose": "7.x || 8.x || ^9.0.0-0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@masteringjs/eslint-config": "0.1.1",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"eslint": "9.30.0",
|
|
33
33
|
"express": "4.x",
|
|
34
34
|
"mocha": "10.2.0",
|
|
35
|
-
"mongoose": "
|
|
35
|
+
"mongoose": "9.x"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"lint": "eslint .",
|