@mongoosejs/studio 0.1.19 → 0.2.0
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/backend/actions/ChatMessage/executeScript.js +4 -1
- package/backend/actions/ChatThread/createChatMessage.js +28 -22
- package/backend/actions/Model/getDocument.js +2 -1
- package/backend/actions/Model/getDocuments.js +3 -2
- package/backend/actions/Model/getDocumentsStream.js +3 -2
- package/backend/helpers/evaluateFilter.js +38 -1
- package/backend/helpers/getRefFromSchemaType.js +5 -0
- package/express.js +4 -2
- package/frontend/public/app.js +704 -405
- package/frontend/public/index.html +1 -1
- package/frontend/public/style.css +1 -1
- package/frontend/public/tw.css +81 -62
- package/frontend/src/_util/document-search-autocomplete.js +229 -0
- package/frontend/src/chat/chat-message-script/chat-message-script.html +27 -20
- package/frontend/src/chat/chat.html +20 -17
- package/frontend/src/chat/chat.js +2 -0
- package/frontend/src/document/document.css +1 -8
- package/frontend/src/document/document.html +202 -164
- package/frontend/src/document/document.js +1 -0
- package/frontend/src/document-details/document-details.html +1 -11
- package/frontend/src/document-details/document-details.js +43 -1
- package/frontend/src/document-details/document-property/document-property.html +4 -4
- package/frontend/src/index.js +36 -15
- package/frontend/src/json-node/json-node.html +118 -0
- package/frontend/src/json-node/json-node.js +272 -0
- package/frontend/src/list-array/list-array.html +15 -3
- package/frontend/src/list-array/list-array.js +21 -3
- package/frontend/src/list-default/list-default.js +2 -2
- package/frontend/src/list-json/json-node.html +1 -1
- package/frontend/src/list-json/list-json.html +1 -1
- package/frontend/src/list-json/list-json.js +11 -248
- package/frontend/src/list-subdocument/list-subdocument.html +13 -4
- package/frontend/src/list-subdocument/list-subdocument.js +11 -6
- package/frontend/src/models/document-search/document-search.html +1 -1
- package/frontend/src/models/document-search/document-search.js +22 -116
- package/frontend/src/models/models.css +5 -15
- package/frontend/src/models/models.html +34 -34
- package/frontend/src/models/models.js +1 -1
- package/frontend/src/navbar/navbar.html +15 -6
- package/package.json +3 -3
package/frontend/src/index.js
CHANGED
|
@@ -85,42 +85,63 @@ app.component('app-component', {
|
|
|
85
85
|
if (hashParams.has('code')) {
|
|
86
86
|
const code = hashParams.get('code');
|
|
87
87
|
const provider = hashParams.get('provider');
|
|
88
|
+
|
|
89
|
+
let user;
|
|
90
|
+
let accessToken;
|
|
91
|
+
let roles;
|
|
88
92
|
try {
|
|
89
|
-
|
|
93
|
+
({ accessToken, user, roles } = provider === 'github' ? await mothership.github(code) : await mothership.google(code));
|
|
90
94
|
if (roles == null) {
|
|
91
95
|
this.authError = 'You are not authorized to access this workspace';
|
|
92
96
|
this.status = 'loaded';
|
|
93
97
|
return;
|
|
94
98
|
}
|
|
95
|
-
this.user = user;
|
|
96
|
-
this.roles = roles;
|
|
97
|
-
window.localStorage.setItem('_mongooseStudioAccessToken', accessToken._id);
|
|
98
99
|
} catch (err) {
|
|
99
100
|
this.authError = 'An error occurred while logging in. Please try again.';
|
|
100
101
|
this.status = 'loaded';
|
|
101
102
|
return;
|
|
102
|
-
} finally {
|
|
103
|
-
setTimeout(() => {
|
|
104
|
-
this.$router.replace(this.$router.currentRoute.value.path);
|
|
105
|
-
}, 0);
|
|
106
103
|
}
|
|
107
104
|
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
try {
|
|
106
|
+
const { nodeEnv } = await api.status();
|
|
107
|
+
this.nodeEnv = nodeEnv;
|
|
108
|
+
} catch (err) {
|
|
109
|
+
this.authError = 'Error connecting to Mongoose Studio API: ' + err.response?.data?.message ?? err.message;
|
|
110
|
+
this.status = 'loaded';
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this.user = user;
|
|
115
|
+
this.roles = roles;
|
|
116
|
+
window.localStorage.setItem('_mongooseStudioAccessToken', accessToken._id);
|
|
117
|
+
setTimeout(() => {
|
|
118
|
+
this.$router.replace(this.$router.currentRoute.value.path);
|
|
119
|
+
}, 0);
|
|
110
120
|
} else {
|
|
111
121
|
const token = window.localStorage.getItem('_mongooseStudioAccessToken');
|
|
112
122
|
if (token) {
|
|
113
123
|
const { user, roles } = await mothership.me();
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const { nodeEnv } = await api.status();
|
|
127
|
+
this.nodeEnv = nodeEnv;
|
|
128
|
+
} catch (err) {
|
|
129
|
+
this.authError = 'Error connecting to Mongoose Studio API: ' + (err.response?.data?.message ?? err.message);
|
|
130
|
+
this.status = 'loaded';
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
114
134
|
this.user = user;
|
|
115
135
|
this.roles = roles;
|
|
116
|
-
|
|
117
|
-
const { nodeEnv } = await api.status();
|
|
118
|
-
this.nodeEnv = nodeEnv;
|
|
119
136
|
}
|
|
120
137
|
}
|
|
121
138
|
} else {
|
|
122
|
-
|
|
123
|
-
|
|
139
|
+
try {
|
|
140
|
+
const { nodeEnv } = await api.status();
|
|
141
|
+
this.nodeEnv = nodeEnv;
|
|
142
|
+
} catch (err) {
|
|
143
|
+
this.authError = 'Error connecting to Mongoose Studio API: ' + (err.response?.data?.message ?? err.message);
|
|
144
|
+
}
|
|
124
145
|
}
|
|
125
146
|
|
|
126
147
|
this.status = 'loaded';
|
|
@@ -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()"
|
|
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>
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const template = require('./json-node.html');
|
|
4
|
+
|
|
5
|
+
module.exports = app => app.component('json-node', {
|
|
6
|
+
name: 'JsonNode',
|
|
7
|
+
template: template,
|
|
8
|
+
props: {
|
|
9
|
+
nodeKey: {
|
|
10
|
+
type: [String, Number],
|
|
11
|
+
default: null
|
|
12
|
+
},
|
|
13
|
+
value: {
|
|
14
|
+
required: true
|
|
15
|
+
},
|
|
16
|
+
level: {
|
|
17
|
+
type: Number,
|
|
18
|
+
required: true
|
|
19
|
+
},
|
|
20
|
+
isLast: {
|
|
21
|
+
type: Boolean,
|
|
22
|
+
default: false
|
|
23
|
+
},
|
|
24
|
+
path: {
|
|
25
|
+
type: String,
|
|
26
|
+
required: true
|
|
27
|
+
},
|
|
28
|
+
toggleCollapse: {
|
|
29
|
+
type: Function,
|
|
30
|
+
required: true
|
|
31
|
+
},
|
|
32
|
+
isCollapsed: {
|
|
33
|
+
type: Function,
|
|
34
|
+
required: true
|
|
35
|
+
},
|
|
36
|
+
createChildPath: {
|
|
37
|
+
type: Function,
|
|
38
|
+
required: true
|
|
39
|
+
},
|
|
40
|
+
indentSize: {
|
|
41
|
+
type: Number,
|
|
42
|
+
required: true
|
|
43
|
+
},
|
|
44
|
+
maxTopLevelFields: {
|
|
45
|
+
type: Number,
|
|
46
|
+
default: null
|
|
47
|
+
},
|
|
48
|
+
topLevelExpanded: {
|
|
49
|
+
type: Boolean,
|
|
50
|
+
default: false
|
|
51
|
+
},
|
|
52
|
+
expandTopLevel: {
|
|
53
|
+
type: Function,
|
|
54
|
+
default: null
|
|
55
|
+
},
|
|
56
|
+
references: {
|
|
57
|
+
type: Object,
|
|
58
|
+
default: () => ({})
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
computed: {
|
|
62
|
+
hasKey() {
|
|
63
|
+
return this.nodeKey !== null && this.nodeKey !== undefined;
|
|
64
|
+
},
|
|
65
|
+
isRoot() {
|
|
66
|
+
return this.path === 'root';
|
|
67
|
+
},
|
|
68
|
+
isArray() {
|
|
69
|
+
return Array.isArray(this.value);
|
|
70
|
+
},
|
|
71
|
+
isObject() {
|
|
72
|
+
if (this.value === null || this.isArray) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
return Object.prototype.toString.call(this.value) === '[object Object]';
|
|
76
|
+
},
|
|
77
|
+
isComplex() {
|
|
78
|
+
return this.isArray || this.isObject;
|
|
79
|
+
},
|
|
80
|
+
children() {
|
|
81
|
+
if (!this.isComplex) {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
if (this.isArray) {
|
|
85
|
+
return this.value.map((childValue, index) => ({
|
|
86
|
+
displayKey: null,
|
|
87
|
+
value: childValue,
|
|
88
|
+
isLast: index === this.value.length - 1,
|
|
89
|
+
path: this.createChildPath(this.path, index, true)
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
const keys = Object.keys(this.value);
|
|
93
|
+
const visibleKeys = this.visibleObjectKeys(keys);
|
|
94
|
+
const hasHidden = this.hasHiddenRootChildren;
|
|
95
|
+
return visibleKeys.map((key, index) => ({
|
|
96
|
+
displayKey: key,
|
|
97
|
+
value: this.value[key],
|
|
98
|
+
isLast: !hasHidden && index === visibleKeys.length - 1,
|
|
99
|
+
path: this.createChildPath(this.path, key, false)
|
|
100
|
+
}));
|
|
101
|
+
},
|
|
102
|
+
hasChildren() {
|
|
103
|
+
return this.children.length > 0;
|
|
104
|
+
},
|
|
105
|
+
totalObjectChildCount() {
|
|
106
|
+
if (!this.isObject) {
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
return Object.keys(this.value).length;
|
|
110
|
+
},
|
|
111
|
+
hasHiddenRootChildren() {
|
|
112
|
+
if (!this.isRoot || !this.isObject) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
if (this.topLevelExpanded) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
if (typeof this.maxTopLevelFields !== 'number') {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return this.totalObjectChildCount > this.maxTopLevelFields;
|
|
122
|
+
},
|
|
123
|
+
hiddenRootChildrenCount() {
|
|
124
|
+
if (!this.hasHiddenRootChildren) {
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
return this.totalObjectChildCount - this.maxTopLevelFields;
|
|
128
|
+
},
|
|
129
|
+
showToggle() {
|
|
130
|
+
return this.hasChildren && !this.isRoot;
|
|
131
|
+
},
|
|
132
|
+
openingBracket() {
|
|
133
|
+
return this.isArray ? '[' : '{';
|
|
134
|
+
},
|
|
135
|
+
closingBracket() {
|
|
136
|
+
return this.isArray ? ']' : '}';
|
|
137
|
+
},
|
|
138
|
+
isCollapsedNode() {
|
|
139
|
+
return this.isCollapsed(this.path);
|
|
140
|
+
},
|
|
141
|
+
formattedValue() {
|
|
142
|
+
if (typeof this.value === 'bigint') {
|
|
143
|
+
return `${this.value.toString()}n`;
|
|
144
|
+
}
|
|
145
|
+
const stringified = JSON.stringify(this.value);
|
|
146
|
+
if (stringified === undefined) {
|
|
147
|
+
if (typeof this.value === 'symbol') {
|
|
148
|
+
return this.value.toString();
|
|
149
|
+
}
|
|
150
|
+
return String(this.value);
|
|
151
|
+
}
|
|
152
|
+
return stringified;
|
|
153
|
+
},
|
|
154
|
+
valueClasses() {
|
|
155
|
+
const classes = ['text-slate-700'];
|
|
156
|
+
if (this.value === null) {
|
|
157
|
+
classes.push('text-gray-500', 'italic');
|
|
158
|
+
return classes;
|
|
159
|
+
}
|
|
160
|
+
const type = typeof this.value;
|
|
161
|
+
if (type === 'string') {
|
|
162
|
+
classes.push('text-emerald-600');
|
|
163
|
+
return classes;
|
|
164
|
+
}
|
|
165
|
+
if (type === 'number' || type === 'bigint') {
|
|
166
|
+
classes.push('text-amber-600');
|
|
167
|
+
return classes;
|
|
168
|
+
}
|
|
169
|
+
if (type === 'boolean') {
|
|
170
|
+
classes.push('text-violet-600');
|
|
171
|
+
return classes;
|
|
172
|
+
}
|
|
173
|
+
if (type === 'undefined') {
|
|
174
|
+
classes.push('text-gray-500');
|
|
175
|
+
return classes;
|
|
176
|
+
}
|
|
177
|
+
return classes;
|
|
178
|
+
},
|
|
179
|
+
comma() {
|
|
180
|
+
return this.isLast ? '' : ',';
|
|
181
|
+
},
|
|
182
|
+
indentStyle() {
|
|
183
|
+
return {
|
|
184
|
+
paddingLeft: `${this.level * this.indentSize}px`
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
hiddenChildrenLabel() {
|
|
188
|
+
if (!this.hasHiddenRootChildren) {
|
|
189
|
+
return '';
|
|
190
|
+
}
|
|
191
|
+
const count = this.hiddenRootChildrenCount;
|
|
192
|
+
const suffix = count === 1 ? 'field' : 'fields';
|
|
193
|
+
return `${count} more ${suffix}`;
|
|
194
|
+
},
|
|
195
|
+
hiddenChildrenTooltip() {
|
|
196
|
+
return this.hiddenChildrenLabel;
|
|
197
|
+
},
|
|
198
|
+
normalizedPath() {
|
|
199
|
+
if (typeof this.path !== 'string') {
|
|
200
|
+
return '';
|
|
201
|
+
}
|
|
202
|
+
return this.path
|
|
203
|
+
.replace(/^root\.?/, '')
|
|
204
|
+
.replace(/\[\d+\]/g, '')
|
|
205
|
+
.replace(/^\./, '');
|
|
206
|
+
},
|
|
207
|
+
referenceModel() {
|
|
208
|
+
if (!this.normalizedPath || !this.references) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
return this.references[this.normalizedPath] || null;
|
|
212
|
+
},
|
|
213
|
+
shouldShowReferenceLink() {
|
|
214
|
+
return this.referenceId != null;
|
|
215
|
+
},
|
|
216
|
+
referenceId() {
|
|
217
|
+
if (!this.referenceModel) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
if (this.value == null) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
const type = typeof this.value;
|
|
224
|
+
if (type === 'string' || type === 'number' || type === 'bigint') {
|
|
225
|
+
return String(this.value);
|
|
226
|
+
}
|
|
227
|
+
if (type === 'object') {
|
|
228
|
+
if (this.value._id != null) {
|
|
229
|
+
return String(this.value._id);
|
|
230
|
+
}
|
|
231
|
+
if (typeof this.value.toString === 'function') {
|
|
232
|
+
const stringified = this.value.toString();
|
|
233
|
+
if (typeof stringified === 'string' && stringified !== '[object Object]') {
|
|
234
|
+
return stringified;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
methods: {
|
|
242
|
+
visibleObjectKeys(keys) {
|
|
243
|
+
if (!this.isRoot || this.topLevelExpanded) {
|
|
244
|
+
return keys;
|
|
245
|
+
}
|
|
246
|
+
if (typeof this.maxTopLevelFields !== 'number') {
|
|
247
|
+
return keys;
|
|
248
|
+
}
|
|
249
|
+
if (keys.length <= this.maxTopLevelFields) {
|
|
250
|
+
return keys;
|
|
251
|
+
}
|
|
252
|
+
return keys.slice(0, this.maxTopLevelFields);
|
|
253
|
+
},
|
|
254
|
+
handleToggle() {
|
|
255
|
+
if (!this.isRoot) {
|
|
256
|
+
this.toggleCollapse(this.path);
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
handleExpandTopLevel() {
|
|
260
|
+
if (this.isRoot && typeof this.expandTopLevel === 'function') {
|
|
261
|
+
this.expandTopLevel();
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
goToReference() {
|
|
265
|
+
const id = this.referenceId;
|
|
266
|
+
if (!this.referenceModel || id == null) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
this.$router.push({ path: `/model/${this.referenceModel}/document/${id}` });
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
});
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
-
<div class="list-array">
|
|
2
|
-
<
|
|
3
|
-
|
|
1
|
+
<div class="list-array tooltip">
|
|
2
|
+
<div>{{displayValue}}</div>
|
|
3
|
+
<div class="tooltiptext" style="display:flex; width: 100%; justify-content: space-around; align-items: center; min-width: 180px;">
|
|
4
|
+
<div class="tooltiptextchild" @click.stop="showViewDataModal = true">View data</div>
|
|
5
|
+
<div class="tooltiptextchild" @click.stop="copyText(value)">Copy 📋</div>
|
|
6
|
+
</div>
|
|
7
|
+
<modal ref="viewDataModal" v-if="showViewDataModal" containerClass="!h-[90vh] !w-[90vw]">
|
|
8
|
+
<template #body>
|
|
9
|
+
<div @click.stop class="w-full h-full cursor-auto">
|
|
10
|
+
<div class="modal-exit" @click="showViewDataModal = false">×</div>
|
|
11
|
+
<list-json :value="value" :expandedFields="Object.keys(value || []).map(key => `root[${key}]`)" />
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
</modal>
|
|
15
|
+
</div>
|
|
@@ -5,12 +5,30 @@ const template = require('./list-array.html');
|
|
|
5
5
|
module.exports = app => app.component('list-array', {
|
|
6
6
|
template: template,
|
|
7
7
|
props: ['value'],
|
|
8
|
+
data: () => ({ showViewDataModal: false }),
|
|
8
9
|
computed: {
|
|
9
10
|
displayValue() {
|
|
10
|
-
|
|
11
|
+
if (this.value == null) {
|
|
12
|
+
return this.value;
|
|
13
|
+
}
|
|
14
|
+
const value = JSON.stringify(this.value);
|
|
15
|
+
if (value.length > 50) {
|
|
16
|
+
return `${value.slice(0, 50)}…`;
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
11
19
|
}
|
|
12
20
|
},
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
methods: {
|
|
22
|
+
copyText(value) {
|
|
23
|
+
const storage = document.createElement('textarea');
|
|
24
|
+
storage.value = JSON.stringify(value);
|
|
25
|
+
const elem = this.$el;
|
|
26
|
+
elem.appendChild(storage);
|
|
27
|
+
storage.select();
|
|
28
|
+
storage.setSelectionRange(0, 99999);
|
|
29
|
+
document.execCommand('copy');
|
|
30
|
+
elem.removeChild(storage);
|
|
31
|
+
this.$toast.success('Text copied!');
|
|
32
|
+
}
|
|
15
33
|
}
|
|
16
34
|
});
|
|
@@ -32,7 +32,7 @@ module.exports = app => app.component('list-default', {
|
|
|
32
32
|
if (this.value === undefined) {
|
|
33
33
|
return 'undefined';
|
|
34
34
|
}
|
|
35
|
-
if (this.value.length > 30) {
|
|
35
|
+
if (this.value.length > 30 && typeof this.value === 'string') {
|
|
36
36
|
return this.value.substring(0, 30) + '...';
|
|
37
37
|
}
|
|
38
38
|
return this.value;
|
|
@@ -41,4 +41,4 @@ module.exports = app => app.component('list-default', {
|
|
|
41
41
|
return this.allude;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
});
|
|
44
|
+
});
|