@mongoosejs/studio 0.0.136 → 0.0.138
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/README.md +30 -0
- package/frontend/public/app.js +412 -68
- package/frontend/public/tw.css +111 -0
- package/frontend/src/list-json/list-json.html +17 -3
- package/frontend/src/list-json/list-json.js +350 -25
- package/frontend/src/models/models.css +1 -0
- package/frontend/src/models/models.html +19 -4
- package/frontend/src/models/models.js +58 -27
- package/next.js +97 -0
- package/package.json +1 -1
- package/frontend/src/list-json/list-json.css +0 -3
package/frontend/public/app.js
CHANGED
|
@@ -126,7 +126,6 @@ var map = {
|
|
|
126
126
|
"./list-default/list-default.html": "./frontend/src/list-default/list-default.html",
|
|
127
127
|
"./list-default/list-default.js": "./frontend/src/list-default/list-default.js",
|
|
128
128
|
"./list-json/list-json": "./frontend/src/list-json/list-json.js",
|
|
129
|
-
"./list-json/list-json.css": "./frontend/src/list-json/list-json.css",
|
|
130
129
|
"./list-json/list-json.html": "./frontend/src/list-json/list-json.html",
|
|
131
130
|
"./list-json/list-json.js": "./frontend/src/list-json/list-json.js",
|
|
132
131
|
"./list-mixed/list-mixed": "./frontend/src/list-mixed/list-mixed.js",
|
|
@@ -3565,17 +3564,6 @@ module.exports = app => app.component('list-default', {
|
|
|
3565
3564
|
|
|
3566
3565
|
/***/ }),
|
|
3567
3566
|
|
|
3568
|
-
/***/ "./frontend/src/list-json/list-json.css":
|
|
3569
|
-
/*!**********************************************!*\
|
|
3570
|
-
!*** ./frontend/src/list-json/list-json.css ***!
|
|
3571
|
-
\**********************************************/
|
|
3572
|
-
/***/ ((module) => {
|
|
3573
|
-
|
|
3574
|
-
"use strict";
|
|
3575
|
-
module.exports = ".list-json {\n width: 100%;\n}";
|
|
3576
|
-
|
|
3577
|
-
/***/ }),
|
|
3578
|
-
|
|
3579
3567
|
/***/ "./frontend/src/list-json/list-json.html":
|
|
3580
3568
|
/*!***********************************************!*\
|
|
3581
3569
|
!*** ./frontend/src/list-json/list-json.html ***!
|
|
@@ -3583,7 +3571,7 @@ module.exports = ".list-json {\n width: 100%;\n}";
|
|
|
3583
3571
|
/***/ ((module) => {
|
|
3584
3572
|
|
|
3585
3573
|
"use strict";
|
|
3586
|
-
module.exports = "<div class=\"
|
|
3574
|
+
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";
|
|
3587
3575
|
|
|
3588
3576
|
/***/ }),
|
|
3589
3577
|
|
|
@@ -3596,42 +3584,367 @@ module.exports = "<div class=\"list-json tooltip\">\n <pre><code ref=\"JSONCode
|
|
|
3596
3584
|
"use strict";
|
|
3597
3585
|
|
|
3598
3586
|
|
|
3599
|
-
const api = __webpack_require__(/*! ../api */ "./frontend/src/api.js");
|
|
3600
3587
|
const template = __webpack_require__(/*! ./list-json.html */ "./frontend/src/list-json/list-json.html");
|
|
3601
3588
|
|
|
3602
|
-
const
|
|
3603
|
-
|
|
3604
|
-
|
|
3589
|
+
const JsonNodeTemplate = `
|
|
3590
|
+
<div>
|
|
3591
|
+
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
|
|
3592
|
+
<button
|
|
3593
|
+
v-if="showToggle"
|
|
3594
|
+
type="button"
|
|
3595
|
+
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"
|
|
3596
|
+
@click.stop="handleToggle"
|
|
3597
|
+
>
|
|
3598
|
+
{{ isCollapsedNode ? '+' : '-' }}
|
|
3599
|
+
</button>
|
|
3600
|
+
<span v-else class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible flex-shrink-0"></span>
|
|
3601
|
+
<template v-if="hasKey">
|
|
3602
|
+
<span class="text-blue-600">"{{ nodeKey }}"</span><span>: </span>
|
|
3603
|
+
</template>
|
|
3604
|
+
<template v-if="isComplex">
|
|
3605
|
+
<template v-if="hasChildren">
|
|
3606
|
+
<span>{{ openingBracket }}</span>
|
|
3607
|
+
<span v-if="isCollapsedNode" class="mx-1">…</span>
|
|
3608
|
+
<span v-if="isCollapsedNode">{{ closingBracket }}{{ comma }}</span>
|
|
3609
|
+
</template>
|
|
3610
|
+
<template v-else>
|
|
3611
|
+
<span>{{ openingBracket }}{{ closingBracket }}{{ comma }}</span>
|
|
3612
|
+
</template>
|
|
3613
|
+
</template>
|
|
3614
|
+
<template v-else>
|
|
3615
|
+
<!--
|
|
3616
|
+
If value is a string and overflows its container (i.e. goes over one line), show an ellipsis.
|
|
3617
|
+
This is done via CSS ellipsis strategy.
|
|
3618
|
+
-->
|
|
3619
|
+
<span
|
|
3620
|
+
:class="valueClasses"
|
|
3621
|
+
:style="typeof value === 'string'
|
|
3622
|
+
? {
|
|
3623
|
+
display: 'inline-block',
|
|
3624
|
+
maxWidth: '100%',
|
|
3625
|
+
overflow: 'hidden',
|
|
3626
|
+
textOverflow: 'ellipsis',
|
|
3627
|
+
whiteSpace: 'nowrap',
|
|
3628
|
+
verticalAlign: 'bottom'
|
|
3629
|
+
}
|
|
3630
|
+
: {}"
|
|
3631
|
+
:title="typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined"
|
|
3632
|
+
>
|
|
3633
|
+
{{ formattedValue }}{{ comma }}
|
|
3634
|
+
</span>
|
|
3635
|
+
</template>
|
|
3636
|
+
</div>
|
|
3637
|
+
<template v-if="isComplex && hasChildren && !isCollapsedNode">
|
|
3638
|
+
<json-node
|
|
3639
|
+
v-for="child in children"
|
|
3640
|
+
:key="child.path"
|
|
3641
|
+
:node-key="child.displayKey"
|
|
3642
|
+
:value="child.value"
|
|
3643
|
+
:level="level + 1"
|
|
3644
|
+
:is-last="child.isLast"
|
|
3645
|
+
:path="child.path"
|
|
3646
|
+
:toggle-collapse="toggleCollapse"
|
|
3647
|
+
:is-collapsed="isCollapsed"
|
|
3648
|
+
:create-child-path="createChildPath"
|
|
3649
|
+
:indent-size="indentSize"
|
|
3650
|
+
:max-top-level-fields="maxTopLevelFields"
|
|
3651
|
+
:top-level-expanded="topLevelExpanded"
|
|
3652
|
+
:expand-top-level="expandTopLevel"
|
|
3653
|
+
></json-node>
|
|
3654
|
+
<div
|
|
3655
|
+
v-if="hasHiddenRootChildren"
|
|
3656
|
+
class="flex items-baseline whitespace-pre"
|
|
3657
|
+
:style="indentStyle"
|
|
3658
|
+
>
|
|
3659
|
+
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
|
|
3660
|
+
<button
|
|
3661
|
+
type="button"
|
|
3662
|
+
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"
|
|
3663
|
+
:title="hiddenChildrenTooltip"
|
|
3664
|
+
@click.stop="handleExpandTopLevel"
|
|
3665
|
+
>
|
|
3666
|
+
<span aria-hidden="true">{{hiddenChildrenLabel}}…</span>
|
|
3667
|
+
</button>
|
|
3668
|
+
</div>
|
|
3669
|
+
<div class="flex items-baseline whitespace-pre" :style="indentStyle">
|
|
3670
|
+
<span class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible"></span>
|
|
3671
|
+
<span>{{ closingBracket }}{{ comma }}</span>
|
|
3672
|
+
</div>
|
|
3673
|
+
</template>
|
|
3674
|
+
</div>
|
|
3675
|
+
`;
|
|
3605
3676
|
|
|
3606
3677
|
module.exports = app => app.component('list-json', {
|
|
3607
3678
|
template: template,
|
|
3608
3679
|
props: ['value'],
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3680
|
+
data() {
|
|
3681
|
+
return {
|
|
3682
|
+
collapsedMap: {},
|
|
3683
|
+
indentSize: 16,
|
|
3684
|
+
maxTopLevelFields: 15,
|
|
3685
|
+
topLevelExpanded: false
|
|
3686
|
+
};
|
|
3687
|
+
},
|
|
3688
|
+
watch: {
|
|
3689
|
+
value: {
|
|
3690
|
+
handler() {
|
|
3691
|
+
this.resetCollapse();
|
|
3692
|
+
}
|
|
3612
3693
|
}
|
|
3613
3694
|
},
|
|
3695
|
+
created() {
|
|
3696
|
+
this.resetCollapse();
|
|
3697
|
+
},
|
|
3614
3698
|
methods: {
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3699
|
+
resetCollapse() {
|
|
3700
|
+
this.collapsedMap = {};
|
|
3701
|
+
this.topLevelExpanded = false;
|
|
3702
|
+
},
|
|
3703
|
+
toggleCollapse(path) {
|
|
3704
|
+
const current = this.isPathCollapsed(path);
|
|
3705
|
+
this.collapsedMap = Object.assign({}, this.collapsedMap, { [path]: !current });
|
|
3706
|
+
},
|
|
3707
|
+
isPathCollapsed(path) {
|
|
3708
|
+
if (path === 'root') {
|
|
3709
|
+
return false;
|
|
3710
|
+
}
|
|
3711
|
+
if (Object.prototype.hasOwnProperty.call(this.collapsedMap, path)) {
|
|
3712
|
+
return this.collapsedMap[path];
|
|
3713
|
+
}
|
|
3714
|
+
return true;
|
|
3715
|
+
},
|
|
3716
|
+
createChildPath(parentPath, childKey, isArray) {
|
|
3717
|
+
if (parentPath == null || parentPath === '') {
|
|
3718
|
+
return isArray ? `[${childKey}]` : `${childKey}`;
|
|
3719
|
+
}
|
|
3720
|
+
if (parentPath === 'root') {
|
|
3721
|
+
return isArray ? `root[${childKey}]` : `root.${childKey}`;
|
|
3722
|
+
}
|
|
3723
|
+
if (isArray) {
|
|
3724
|
+
return `${parentPath}[${childKey}]`;
|
|
3725
|
+
}
|
|
3726
|
+
return `${parentPath}.${childKey}`;
|
|
3727
|
+
},
|
|
3728
|
+
expandTopLevel() {
|
|
3729
|
+
this.topLevelExpanded = true;
|
|
3631
3730
|
}
|
|
3632
3731
|
},
|
|
3633
|
-
|
|
3634
|
-
|
|
3732
|
+
components: {
|
|
3733
|
+
JsonNode: {
|
|
3734
|
+
name: 'JsonNode',
|
|
3735
|
+
template: JsonNodeTemplate,
|
|
3736
|
+
props: {
|
|
3737
|
+
nodeKey: {
|
|
3738
|
+
type: [String, Number],
|
|
3739
|
+
default: null
|
|
3740
|
+
},
|
|
3741
|
+
value: {
|
|
3742
|
+
required: true
|
|
3743
|
+
},
|
|
3744
|
+
level: {
|
|
3745
|
+
type: Number,
|
|
3746
|
+
required: true
|
|
3747
|
+
},
|
|
3748
|
+
isLast: {
|
|
3749
|
+
type: Boolean,
|
|
3750
|
+
default: false
|
|
3751
|
+
},
|
|
3752
|
+
path: {
|
|
3753
|
+
type: String,
|
|
3754
|
+
required: true
|
|
3755
|
+
},
|
|
3756
|
+
toggleCollapse: {
|
|
3757
|
+
type: Function,
|
|
3758
|
+
required: true
|
|
3759
|
+
},
|
|
3760
|
+
isCollapsed: {
|
|
3761
|
+
type: Function,
|
|
3762
|
+
required: true
|
|
3763
|
+
},
|
|
3764
|
+
createChildPath: {
|
|
3765
|
+
type: Function,
|
|
3766
|
+
required: true
|
|
3767
|
+
},
|
|
3768
|
+
indentSize: {
|
|
3769
|
+
type: Number,
|
|
3770
|
+
required: true
|
|
3771
|
+
},
|
|
3772
|
+
maxTopLevelFields: {
|
|
3773
|
+
type: Number,
|
|
3774
|
+
default: null
|
|
3775
|
+
},
|
|
3776
|
+
topLevelExpanded: {
|
|
3777
|
+
type: Boolean,
|
|
3778
|
+
default: false
|
|
3779
|
+
},
|
|
3780
|
+
expandTopLevel: {
|
|
3781
|
+
type: Function,
|
|
3782
|
+
default: null
|
|
3783
|
+
}
|
|
3784
|
+
},
|
|
3785
|
+
computed: {
|
|
3786
|
+
hasKey() {
|
|
3787
|
+
return this.nodeKey !== null && this.nodeKey !== undefined;
|
|
3788
|
+
},
|
|
3789
|
+
isRoot() {
|
|
3790
|
+
return this.path === 'root';
|
|
3791
|
+
},
|
|
3792
|
+
isArray() {
|
|
3793
|
+
return Array.isArray(this.value);
|
|
3794
|
+
},
|
|
3795
|
+
isObject() {
|
|
3796
|
+
if (this.value === null || this.isArray) {
|
|
3797
|
+
return false;
|
|
3798
|
+
}
|
|
3799
|
+
return Object.prototype.toString.call(this.value) === '[object Object]';
|
|
3800
|
+
},
|
|
3801
|
+
isComplex() {
|
|
3802
|
+
return this.isArray || this.isObject;
|
|
3803
|
+
},
|
|
3804
|
+
children() {
|
|
3805
|
+
if (!this.isComplex) {
|
|
3806
|
+
return [];
|
|
3807
|
+
}
|
|
3808
|
+
if (this.isArray) {
|
|
3809
|
+
return this.value.map((childValue, index) => ({
|
|
3810
|
+
displayKey: null,
|
|
3811
|
+
value: childValue,
|
|
3812
|
+
isLast: index === this.value.length - 1,
|
|
3813
|
+
path: this.createChildPath(this.path, index, true)
|
|
3814
|
+
}));
|
|
3815
|
+
}
|
|
3816
|
+
const keys = Object.keys(this.value);
|
|
3817
|
+
const visibleKeys = this.visibleObjectKeys(keys);
|
|
3818
|
+
const hasHidden = this.hasHiddenRootChildren;
|
|
3819
|
+
return visibleKeys.map((key, index) => ({
|
|
3820
|
+
displayKey: key,
|
|
3821
|
+
value: this.value[key],
|
|
3822
|
+
isLast: !hasHidden && index === visibleKeys.length - 1,
|
|
3823
|
+
path: this.createChildPath(this.path, key, false)
|
|
3824
|
+
}));
|
|
3825
|
+
},
|
|
3826
|
+
hasChildren() {
|
|
3827
|
+
return this.children.length > 0;
|
|
3828
|
+
},
|
|
3829
|
+
totalObjectChildCount() {
|
|
3830
|
+
if (!this.isObject) {
|
|
3831
|
+
return 0;
|
|
3832
|
+
}
|
|
3833
|
+
return Object.keys(this.value).length;
|
|
3834
|
+
},
|
|
3835
|
+
hasHiddenRootChildren() {
|
|
3836
|
+
if (!this.isRoot || !this.isObject) {
|
|
3837
|
+
return false;
|
|
3838
|
+
}
|
|
3839
|
+
if (this.topLevelExpanded) {
|
|
3840
|
+
return false;
|
|
3841
|
+
}
|
|
3842
|
+
if (typeof this.maxTopLevelFields !== 'number') {
|
|
3843
|
+
return false;
|
|
3844
|
+
}
|
|
3845
|
+
return this.totalObjectChildCount > this.maxTopLevelFields;
|
|
3846
|
+
},
|
|
3847
|
+
hiddenRootChildrenCount() {
|
|
3848
|
+
if (!this.hasHiddenRootChildren) {
|
|
3849
|
+
return 0;
|
|
3850
|
+
}
|
|
3851
|
+
return this.totalObjectChildCount - this.maxTopLevelFields;
|
|
3852
|
+
},
|
|
3853
|
+
showToggle() {
|
|
3854
|
+
return this.hasChildren && !this.isRoot;
|
|
3855
|
+
},
|
|
3856
|
+
openingBracket() {
|
|
3857
|
+
return this.isArray ? '[' : '{';
|
|
3858
|
+
},
|
|
3859
|
+
closingBracket() {
|
|
3860
|
+
return this.isArray ? ']' : '}';
|
|
3861
|
+
},
|
|
3862
|
+
isCollapsedNode() {
|
|
3863
|
+
return this.isCollapsed(this.path);
|
|
3864
|
+
},
|
|
3865
|
+
formattedValue() {
|
|
3866
|
+
if (typeof this.value === 'bigint') {
|
|
3867
|
+
return `${this.value.toString()}n`;
|
|
3868
|
+
}
|
|
3869
|
+
const stringified = JSON.stringify(this.value);
|
|
3870
|
+
if (stringified === undefined) {
|
|
3871
|
+
if (typeof this.value === 'symbol') {
|
|
3872
|
+
return this.value.toString();
|
|
3873
|
+
}
|
|
3874
|
+
return String(this.value);
|
|
3875
|
+
}
|
|
3876
|
+
return stringified;
|
|
3877
|
+
},
|
|
3878
|
+
valueClasses() {
|
|
3879
|
+
const classes = ['text-slate-700'];
|
|
3880
|
+
if (this.value === null) {
|
|
3881
|
+
classes.push('text-gray-500', 'italic');
|
|
3882
|
+
return classes;
|
|
3883
|
+
}
|
|
3884
|
+
const type = typeof this.value;
|
|
3885
|
+
if (type === 'string') {
|
|
3886
|
+
classes.push('text-emerald-600');
|
|
3887
|
+
return classes;
|
|
3888
|
+
}
|
|
3889
|
+
if (type === 'number' || type === 'bigint') {
|
|
3890
|
+
classes.push('text-amber-600');
|
|
3891
|
+
return classes;
|
|
3892
|
+
}
|
|
3893
|
+
if (type === 'boolean') {
|
|
3894
|
+
classes.push('text-violet-600');
|
|
3895
|
+
return classes;
|
|
3896
|
+
}
|
|
3897
|
+
if (type === 'undefined') {
|
|
3898
|
+
classes.push('text-gray-500');
|
|
3899
|
+
return classes;
|
|
3900
|
+
}
|
|
3901
|
+
return classes;
|
|
3902
|
+
},
|
|
3903
|
+
comma() {
|
|
3904
|
+
return this.isLast ? '' : ',';
|
|
3905
|
+
},
|
|
3906
|
+
indentStyle() {
|
|
3907
|
+
return {
|
|
3908
|
+
paddingLeft: `${this.level * this.indentSize}px`
|
|
3909
|
+
};
|
|
3910
|
+
},
|
|
3911
|
+
hiddenChildrenLabel() {
|
|
3912
|
+
if (!this.hasHiddenRootChildren) {
|
|
3913
|
+
return '';
|
|
3914
|
+
}
|
|
3915
|
+
const count = this.hiddenRootChildrenCount;
|
|
3916
|
+
const suffix = count === 1 ? 'field' : 'fields';
|
|
3917
|
+
return `${count} more ${suffix}`;
|
|
3918
|
+
},
|
|
3919
|
+
hiddenChildrenTooltip() {
|
|
3920
|
+
return this.hiddenChildrenLabel;
|
|
3921
|
+
}
|
|
3922
|
+
},
|
|
3923
|
+
methods: {
|
|
3924
|
+
visibleObjectKeys(keys) {
|
|
3925
|
+
if (!this.isRoot || this.topLevelExpanded) {
|
|
3926
|
+
return keys;
|
|
3927
|
+
}
|
|
3928
|
+
if (typeof this.maxTopLevelFields !== 'number') {
|
|
3929
|
+
return keys;
|
|
3930
|
+
}
|
|
3931
|
+
if (keys.length <= this.maxTopLevelFields) {
|
|
3932
|
+
return keys;
|
|
3933
|
+
}
|
|
3934
|
+
return keys.slice(0, this.maxTopLevelFields);
|
|
3935
|
+
},
|
|
3936
|
+
handleToggle() {
|
|
3937
|
+
if (!this.isRoot) {
|
|
3938
|
+
this.toggleCollapse(this.path);
|
|
3939
|
+
}
|
|
3940
|
+
},
|
|
3941
|
+
handleExpandTopLevel() {
|
|
3942
|
+
if (this.isRoot && typeof this.expandTopLevel === 'function') {
|
|
3943
|
+
this.expandTopLevel();
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3635
3948
|
}
|
|
3636
3949
|
});
|
|
3637
3950
|
|
|
@@ -3909,7 +4222,7 @@ module.exports = app => app.component('modal', {
|
|
|
3909
4222
|
/***/ ((module) => {
|
|
3910
4223
|
|
|
3911
4224
|
"use strict";
|
|
3912
|
-
module.exports = ".models {\n position: relative;\n display: flex;\n flex-direction: row;\n min-height: calc(100% - 56px);\n}\n\n.models button.gray {\n color: black;\n background-color: #eee;\n}\n\n.models .model-selector {\n background-color: #eee;\n flex-grow: 0;\n padding: 15px;\n padding-top: 0px;\n}\n\n.models h1 {\n margin-top: 0px;\n}\n\n.models .documents {\n flex-grow: 1;\n overflow: scroll;\n max-height: calc(100vh - 56px);\n}\n\n.models .documents table {\n /* max-width: -moz-fit-content;\n max-width: fit-content; */\n width: 100%;\n table-layout: auto;\n font-size: small;\n padding: 0;\n margin-right: 1em;\n white-space: nowrap;\n z-index: -1;\n border-collapse: collapse;\n line-height: 1.5em;\n}\n\n.models .documents table th {\n position: sticky;\n top: 42px;\n background-color: white;\n z-index: 1;\n}\n\n.models .documents table th:after {\n content: \"\";\n position: absolute;\n left: 0;\n width: 100%;\n bottom: -1px;\n border-bottom: thin solid rgba(0, 0, 0, 0.12);\n}\n\n.models .documents table tr {\n color: black;\n border-spacing: 0px 0px;\n background-color: white;\n cursor: pointer;\n}\n\n.models .documents table tr:nth-child(even) {\n background-color: #f5f5f5;\n}\n\n.models .documents table tr:hover {\n background-color: #a7b9ff;\n}\n\n.models .documents table th,\ntd {\n border-bottom: thin solid rgba(0, 0, 0, 0.12);\n text-align: left;\n padding: 0 16px;\n height: 48px;\n}\n\n.models textarea {\n font-size: 1.2em;\n}\n\n.models .path-type {\n color: rgba(0, 0, 0, 0.36);\n font-size: 0.8em;\n}\n\n.models .documents-menu {\n position: fixed;\n background-color: white;\n z-index: 1;\n padding: 4px;\n display: flex;\n width: 100vw;\n}\n\n@media (min-width: 1024px) {\n .models .documents-menu {\n width: calc(100vw - 12rem);\n }\n}\n\n.models .documents-menu .search-input {\n flex-grow: 1;\n align-items: center;\n}\n\n.models .search-input input {\n padding: 0.25em 0.5em;\n font-size: 1.1em;\n border: 1px solid #ddd;\n border-radius: 3px;\n width: calc(100% - 1em);\n}\n\n.models .sort-arrow {\n padding-left: 10px;\n padding-right: 10px;\n}\n\n.models .loader {\n width: 100%;\n text-align: center;\n}\n\n.models .loader img {\n height: 4em;\n}\n\n.models .documents .buttons {\n display: inline-flex;\n justify-content: space-around;\n align-items: center;\n}\n";
|
|
4225
|
+
module.exports = ".models {\n position: relative;\n display: flex;\n flex-direction: row;\n min-height: calc(100% - 56px);\n}\n\n.models button.gray {\n color: black;\n background-color: #eee;\n}\n\n.models .model-selector {\n background-color: #eee;\n flex-grow: 0;\n padding: 15px;\n padding-top: 0px;\n}\n\n.models h1 {\n margin-top: 0px;\n}\n\n.models .documents {\n flex-grow: 1;\n overflow: scroll;\n max-height: calc(100vh - 56px);\n}\n\n.models .documents table {\n /* max-width: -moz-fit-content;\n max-width: fit-content; */\n width: 100%;\n table-layout: auto;\n font-size: small;\n padding: 0;\n margin-right: 1em;\n white-space: nowrap;\n z-index: -1;\n border-collapse: collapse;\n line-height: 1.5em;\n}\n\n.models .documents table th {\n position: sticky;\n top: 42px;\n background-color: white;\n z-index: 1;\n}\n\n.models .documents table th:after {\n content: \"\";\n position: absolute;\n left: 0;\n width: 100%;\n bottom: -1px;\n border-bottom: thin solid rgba(0, 0, 0, 0.12);\n}\n\n.models .documents table tr {\n color: black;\n border-spacing: 0px 0px;\n background-color: white;\n cursor: pointer;\n}\n\n.models .documents table tr:nth-child(even) {\n background-color: #f5f5f5;\n}\n\n.models .documents table tr:hover {\n background-color: #a7b9ff;\n}\n\n.models .documents table th,\ntd {\n border-bottom: thin solid rgba(0, 0, 0, 0.12);\n text-align: left;\n padding: 0 16px;\n height: 48px;\n}\n\n.models textarea {\n font-size: 1.2em;\n}\n\n.models .path-type {\n color: rgba(0, 0, 0, 0.36);\n font-size: 0.8em;\n}\n\n.models .documents-menu {\n position: fixed;\n background-color: white;\n z-index: 1;\n padding: 4px;\n display: flex;\n width: 100vw;\n}\n\n@media (min-width: 1024px) {\n .models .documents-menu {\n width: calc(100vw - 12rem);\n }\n}\n\n.models .documents-menu .search-input {\n flex-grow: 1;\n align-items: center;\n}\n\n.models .search-input input {\n padding: 0.25em 0.5em;\n font-size: 1.1em;\n border: 1px solid #ddd;\n border-radius: 3px;\n width: calc(100% - 1em);\n}\n\n.models .sort-arrow {\n padding-left: 10px;\n padding-right: 10px;\n}\n\n.models .loader {\n width: 100%;\n text-align: center;\n}\n\n.models .loader img {\n height: 4em;\n}\n\n.models .documents .buttons {\n display: inline-flex;\n justify-content: space-around;\n align-items: center;\n}\n\n";
|
|
3913
4226
|
|
|
3914
4227
|
/***/ }),
|
|
3915
4228
|
|
|
@@ -3920,7 +4233,7 @@ module.exports = ".models {\n position: relative;\n display: flex;\n flex-dir
|
|
|
3920
4233
|
/***/ ((module) => {
|
|
3921
4234
|
|
|
3922
4235
|
"use strict";
|
|
3923
|
-
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 </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=\"outputType = '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=\"outputType = '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 <table v-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-if=\"outputType === 'json'\">\n <div v-for=\"document in documents\" @click=\"handleDocumentClick(document, $event)\" :key=\"document._id\" :class=\"{ 'bg-blue-200': selectedDocuments.some(x => x._id.toString() === document._id.toString()) }\">\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";
|
|
4236
|
+
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 </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 <table v-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-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";
|
|
3924
4237
|
|
|
3925
4238
|
/***/ }),
|
|
3926
4239
|
|
|
@@ -3971,6 +4284,7 @@ const QUERY_SELECTORS = [
|
|
|
3971
4284
|
appendCSS(__webpack_require__(/*! ./models.css */ "./frontend/src/models/models.css"));
|
|
3972
4285
|
|
|
3973
4286
|
const limit = 20;
|
|
4287
|
+
const OUTPUT_TYPE_STORAGE_KEY = 'studio:model-output-type';
|
|
3974
4288
|
|
|
3975
4289
|
module.exports = app => app.component('models', {
|
|
3976
4290
|
template: template,
|
|
@@ -4013,6 +4327,7 @@ module.exports = app => app.component('models', {
|
|
|
4013
4327
|
created() {
|
|
4014
4328
|
this.currentModel = this.model;
|
|
4015
4329
|
this.buildAutocompleteTrie();
|
|
4330
|
+
this.loadOutputPreference();
|
|
4016
4331
|
},
|
|
4017
4332
|
beforeDestroy() {
|
|
4018
4333
|
document.removeEventListener('scroll', this.onScroll, true);
|
|
@@ -4041,6 +4356,24 @@ module.exports = app => app.component('models', {
|
|
|
4041
4356
|
this.autocompleteTrie.bulkInsert(paths, 10);
|
|
4042
4357
|
}
|
|
4043
4358
|
},
|
|
4359
|
+
loadOutputPreference() {
|
|
4360
|
+
if (typeof window === 'undefined' || !window.localStorage) {
|
|
4361
|
+
return;
|
|
4362
|
+
}
|
|
4363
|
+
const storedPreference = window.localStorage.getItem(OUTPUT_TYPE_STORAGE_KEY);
|
|
4364
|
+
if (storedPreference === 'json' || storedPreference === 'table') {
|
|
4365
|
+
this.outputType = storedPreference;
|
|
4366
|
+
}
|
|
4367
|
+
},
|
|
4368
|
+
setOutputType(type) {
|
|
4369
|
+
if (type !== 'json' && type !== 'table') {
|
|
4370
|
+
return;
|
|
4371
|
+
}
|
|
4372
|
+
this.outputType = type;
|
|
4373
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
4374
|
+
window.localStorage.setItem(OUTPUT_TYPE_STORAGE_KEY, type);
|
|
4375
|
+
}
|
|
4376
|
+
},
|
|
4044
4377
|
buildDocumentFetchParams(options = {}) {
|
|
4045
4378
|
const params = {
|
|
4046
4379
|
model: this.currentModel,
|
|
@@ -4480,41 +4813,52 @@ module.exports = app => app.component('models', {
|
|
|
4480
4813
|
},
|
|
4481
4814
|
handleDocumentClick(document, event) {
|
|
4482
4815
|
if (this.selectMultiple) {
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4816
|
+
this.handleDocumentSelection(document, event);
|
|
4817
|
+
} else {
|
|
4818
|
+
this.openDocument(document);
|
|
4819
|
+
}
|
|
4820
|
+
},
|
|
4821
|
+
handleDocumentContainerClick(document, event) {
|
|
4822
|
+
if (this.selectMultiple) {
|
|
4823
|
+
this.handleDocumentSelection(document, event);
|
|
4824
|
+
}
|
|
4825
|
+
},
|
|
4826
|
+
handleDocumentSelection(document, event) {
|
|
4827
|
+
const documentIndex = this.documents.findIndex(doc => doc._id.toString() == document._id.toString());
|
|
4828
|
+
if (event?.shiftKey && this.selectedDocuments.length > 0) {
|
|
4829
|
+
const anchorIndex = this.lastSelectedIndex;
|
|
4830
|
+
if (anchorIndex != null && anchorIndex !== -1 && documentIndex !== -1) {
|
|
4831
|
+
const start = Math.min(anchorIndex, documentIndex);
|
|
4832
|
+
const end = Math.max(anchorIndex, documentIndex);
|
|
4833
|
+
const selectedDocumentIds = new Set(this.selectedDocuments.map(doc => doc._id.toString()));
|
|
4834
|
+
for (let i = start; i <= end; i++) {
|
|
4835
|
+
const docInRange = this.documents[i];
|
|
4836
|
+
const existsInRange = selectedDocumentIds.has(docInRange._id.toString());
|
|
4837
|
+
if (!existsInRange) {
|
|
4838
|
+
this.selectedDocuments.push(docInRange);
|
|
4496
4839
|
}
|
|
4497
|
-
this.lastSelectedIndex = documentIndex;
|
|
4498
|
-
return;
|
|
4499
4840
|
}
|
|
4841
|
+
this.lastSelectedIndex = documentIndex;
|
|
4842
|
+
return;
|
|
4500
4843
|
}
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
const lastDoc = this.selectedDocuments[this.selectedDocuments.length - 1];
|
|
4508
|
-
this.lastSelectedIndex = this.documents.findIndex(doc => doc._id.toString() == lastDoc._id.toString());
|
|
4509
|
-
}
|
|
4844
|
+
}
|
|
4845
|
+
const index = this.selectedDocuments.findIndex(x => x._id.toString() == document._id.toString());
|
|
4846
|
+
if (index !== -1) {
|
|
4847
|
+
this.selectedDocuments.splice(index, 1);
|
|
4848
|
+
if (this.selectedDocuments.length === 0) {
|
|
4849
|
+
this.lastSelectedIndex = null;
|
|
4510
4850
|
} else {
|
|
4511
|
-
this.selectedDocuments.
|
|
4512
|
-
this.lastSelectedIndex =
|
|
4851
|
+
const lastDoc = this.selectedDocuments[this.selectedDocuments.length - 1];
|
|
4852
|
+
this.lastSelectedIndex = this.documents.findIndex(doc => doc._id.toString() == lastDoc._id.toString());
|
|
4513
4853
|
}
|
|
4514
4854
|
} else {
|
|
4515
|
-
this
|
|
4855
|
+
this.selectedDocuments.push(document);
|
|
4856
|
+
this.lastSelectedIndex = documentIndex;
|
|
4516
4857
|
}
|
|
4517
4858
|
},
|
|
4859
|
+
openDocument(document) {
|
|
4860
|
+
this.$router.push('/model/' + this.currentModel + '/document/' + document._id);
|
|
4861
|
+
},
|
|
4518
4862
|
async deleteDocuments() {
|
|
4519
4863
|
const documentIds = this.selectedDocuments.map(x => x._id);
|
|
4520
4864
|
await api.Model.deleteDocuments({
|
|
@@ -15932,7 +16276,7 @@ module.exports = function stringToParts(str) {
|
|
|
15932
16276
|
/***/ ((module) => {
|
|
15933
16277
|
|
|
15934
16278
|
"use strict";
|
|
15935
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.0.
|
|
16279
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.0.138","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.1.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"},"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":"8.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"}}');
|
|
15936
16280
|
|
|
15937
16281
|
/***/ })
|
|
15938
16282
|
|