@mongoosejs/studio 0.0.70 → 0.0.72
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/Model/createDocument.js +8 -1
- package/backend/actions/Model/deleteDocument.js +8 -1
- package/backend/actions/Model/exportQueryResults.js +3 -3
- package/backend/actions/Model/getIndexes.js +33 -0
- package/backend/actions/Model/index.js +1 -0
- package/backend/actions/Model/updateDocument.js +7 -1
- package/express.js +1 -0
- package/frontend/public/app.js +310 -51
- package/frontend/public/images/duplicate.svg +1 -0
- package/frontend/public/tw.css +27 -0
- package/frontend/src/api.js +53 -7
- package/frontend/src/clone-document/clone-document.css +0 -0
- package/frontend/src/clone-document/clone-document.html +26 -0
- package/frontend/src/clone-document/clone-document.js +72 -0
- package/frontend/src/document/document.html +20 -0
- package/frontend/src/document/document.js +14 -2
- package/frontend/src/export-query-results/export-query-results.html +6 -4
- package/frontend/src/index.js +4 -2
- package/frontend/src/models/models.html +26 -4
- package/frontend/src/models/models.js +41 -2
- package/frontend/src/navbar/navbar.html +4 -4
- package/frontend/src/navbar/navbar.js +20 -2
- package/frontend/src/routes.js +70 -32
- package/package.json +1 -1
package/frontend/public/app.js
CHANGED
|
@@ -67,7 +67,31 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
67
67
|
return client.post('', { action: 'Model.deleteDocument', ...params}).then(res => res.data);
|
|
68
68
|
},
|
|
69
69
|
exportQueryResults(params) {
|
|
70
|
-
|
|
70
|
+
const accessToken = window.localStorage.getItem('_mongooseStudioAccessToken') || null;
|
|
71
|
+
|
|
72
|
+
return fetch(window.MONGOOSE_STUDIO_CONFIG.baseURL + new URLSearchParams({ ...params, action: 'Model.exportQueryResults' }).toString(), {
|
|
73
|
+
method: 'GET',
|
|
74
|
+
headers: {
|
|
75
|
+
'Authorization': `${accessToken}`, // Set your authorization token here
|
|
76
|
+
'Accept': 'text/csv'
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
.then(response => {
|
|
80
|
+
if (!response.ok) {
|
|
81
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
82
|
+
}
|
|
83
|
+
return response.blob();
|
|
84
|
+
})
|
|
85
|
+
.then(blob => {
|
|
86
|
+
const blobURL = window.URL.createObjectURL(blob);
|
|
87
|
+
const anchor = document.createElement('a');
|
|
88
|
+
anchor.href = blobURL;
|
|
89
|
+
anchor.download = 'export.csv';
|
|
90
|
+
document.body.appendChild(anchor);
|
|
91
|
+
anchor.click();
|
|
92
|
+
document.body.removeChild(anchor);
|
|
93
|
+
window.URL.revokeObjectURL(blobURL);
|
|
94
|
+
});
|
|
71
95
|
},
|
|
72
96
|
getDocument: function getDocument(params) {
|
|
73
97
|
return client.post('', { action: 'Model.getDocument', ...params }).then(res => res.data);
|
|
@@ -114,12 +138,31 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
114
138
|
return client.post('/Model/deleteDocument', params).then(res => res.data);
|
|
115
139
|
},
|
|
116
140
|
exportQueryResults(params) {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
141
|
+
const accessToken = window.localStorage.getItem('_mongooseStudioAccessToken') || null;
|
|
142
|
+
|
|
143
|
+
return fetch(window.MONGOOSE_STUDIO_CONFIG.baseURL + '/Model/exportQueryResults?' + new URLSearchParams(params).toString(), {
|
|
144
|
+
method: 'GET',
|
|
145
|
+
headers: {
|
|
146
|
+
'Authorization': `${accessToken}`, // Set your authorization token here
|
|
147
|
+
'Accept': 'text/csv'
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
.then(response => {
|
|
151
|
+
if (!response.ok) {
|
|
152
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
153
|
+
}
|
|
154
|
+
return response.blob();
|
|
155
|
+
})
|
|
156
|
+
.then(blob => {
|
|
157
|
+
const blobURL = window.URL.createObjectURL(blob);
|
|
158
|
+
const anchor = document.createElement('a');
|
|
159
|
+
anchor.href = blobURL;
|
|
160
|
+
anchor.download = 'export.csv';
|
|
161
|
+
document.body.appendChild(anchor);
|
|
162
|
+
anchor.click();
|
|
163
|
+
document.body.removeChild(anchor);
|
|
164
|
+
window.URL.revokeObjectURL(blobURL);
|
|
165
|
+
});
|
|
123
166
|
},
|
|
124
167
|
getDocument: function getDocument(params) {
|
|
125
168
|
return client.post('/Model/getDocument', params).then(res => res.data);
|
|
@@ -127,6 +170,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
127
170
|
getDocuments: function getDocuments(params) {
|
|
128
171
|
return client.post('/Model/getDocuments', params).then(res => res.data);
|
|
129
172
|
},
|
|
173
|
+
getIndexes: function getIndexes(params) {
|
|
174
|
+
return client.post('/Model/getIndexes', params).then(res => res.data);
|
|
175
|
+
},
|
|
130
176
|
listModels: function listModels() {
|
|
131
177
|
return client.post('/Model/listModels', {}).then(res => res.data);
|
|
132
178
|
},
|
|
@@ -212,6 +258,88 @@ module.exports = app => app.component('async-button', {
|
|
|
212
258
|
|
|
213
259
|
/***/ }),
|
|
214
260
|
|
|
261
|
+
/***/ "./frontend/src/clone-document/clone-document.js":
|
|
262
|
+
/*!*******************************************************!*\
|
|
263
|
+
!*** ./frontend/src/clone-document/clone-document.js ***!
|
|
264
|
+
\*******************************************************/
|
|
265
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
266
|
+
|
|
267
|
+
"use strict";
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
const api = __webpack_require__(/*! ../api */ "./frontend/src/api.js");
|
|
271
|
+
|
|
272
|
+
const { BSON, EJSON } = __webpack_require__(/*! bson */ "./node_modules/bson/lib/bson.cjs");
|
|
273
|
+
|
|
274
|
+
const ObjectId = new Proxy(BSON.ObjectId, {
|
|
275
|
+
apply (target, thisArg, argumentsList) {
|
|
276
|
+
return new target(...argumentsList);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
const appendCSS = __webpack_require__(/*! ../appendCSS */ "./frontend/src/appendCSS.js");
|
|
281
|
+
|
|
282
|
+
appendCSS(__webpack_require__(/*! ./clone-document.css */ "./frontend/src/clone-document/clone-document.css"));
|
|
283
|
+
|
|
284
|
+
const template = __webpack_require__(/*! ./clone-document.html */ "./frontend/src/clone-document/clone-document.html")
|
|
285
|
+
|
|
286
|
+
module.exports = app => app.component('clone-document', {
|
|
287
|
+
props: ['currentModel', 'doc', 'schemaPaths'],
|
|
288
|
+
template,
|
|
289
|
+
data: function() {
|
|
290
|
+
return {
|
|
291
|
+
documentData: '',
|
|
292
|
+
editor: null,
|
|
293
|
+
errors: []
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
methods: {
|
|
297
|
+
async cloneDocument() {
|
|
298
|
+
const data = EJSON.serialize(eval(`(${this.editor.getValue()})`));
|
|
299
|
+
const { doc } = await api.Model.createDocument({ model: this.currentModel, data }).catch(err => {
|
|
300
|
+
if (err.response?.data?.message) {
|
|
301
|
+
console.log(err.response.data);
|
|
302
|
+
const message = err.response.data.message.split(": ").slice(1).join(": ");
|
|
303
|
+
this.errors = message.split(',').map(error => {
|
|
304
|
+
return error.split(': ').slice(1).join(': ').trim();
|
|
305
|
+
})
|
|
306
|
+
throw new Error(err.response?.data?.message);
|
|
307
|
+
}
|
|
308
|
+
throw err;
|
|
309
|
+
});
|
|
310
|
+
this.errors.length = 0;
|
|
311
|
+
this.$emit('close', doc);
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
mounted: function() {
|
|
315
|
+
const pathsToClone = this.schemaPaths.map(x => x.path);
|
|
316
|
+
|
|
317
|
+
// Create a filtered version of the document data
|
|
318
|
+
const filteredDoc = {};
|
|
319
|
+
pathsToClone.forEach(path => {
|
|
320
|
+
const value = this.doc[path];
|
|
321
|
+
if (value !== undefined) {
|
|
322
|
+
filteredDoc[path] = value;
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// Replace _id with a new ObjectId
|
|
327
|
+
if (pathsToClone.includes('_id')) {
|
|
328
|
+
filteredDoc._id = new ObjectId();
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
this.documentData = JSON.stringify(filteredDoc, null, 2);
|
|
332
|
+
this.$refs.codeEditor.value = this.documentData;
|
|
333
|
+
this.editor = CodeMirror.fromTextArea(this.$refs.codeEditor, {
|
|
334
|
+
mode: 'javascript',
|
|
335
|
+
lineNumbers: true,
|
|
336
|
+
smartIndent: false
|
|
337
|
+
});
|
|
338
|
+
},
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
/***/ }),
|
|
342
|
+
|
|
215
343
|
/***/ "./frontend/src/create-dashboard/create-dashboard.js":
|
|
216
344
|
/*!***********************************************************!*\
|
|
217
345
|
!*** ./frontend/src/create-dashboard/create-dashboard.js ***!
|
|
@@ -930,7 +1058,7 @@ appendCSS(__webpack_require__(/*! ./document.css */ "./frontend/src/document/doc
|
|
|
930
1058
|
|
|
931
1059
|
module.exports = app => app.component('document', {
|
|
932
1060
|
template: template,
|
|
933
|
-
props: ['model', 'documentId'],
|
|
1061
|
+
props: ['model', 'documentId', 'user', 'roles'],
|
|
934
1062
|
data: () => ({
|
|
935
1063
|
schemaPaths: [],
|
|
936
1064
|
status: 'init',
|
|
@@ -940,7 +1068,8 @@ module.exports = app => app.component('document', {
|
|
|
940
1068
|
editting: false,
|
|
941
1069
|
virtuals: [],
|
|
942
1070
|
shouldShowConfirmModal: false,
|
|
943
|
-
shouldShowDeleteModal: false
|
|
1071
|
+
shouldShowDeleteModal: false,
|
|
1072
|
+
shouldShowCloneModal: false
|
|
944
1073
|
}),
|
|
945
1074
|
async mounted() {
|
|
946
1075
|
window.pageState = this;
|
|
@@ -958,6 +1087,14 @@ module.exports = app => app.component('document', {
|
|
|
958
1087
|
}).map(key => schemaPaths[key]);
|
|
959
1088
|
this.status = 'loaded';
|
|
960
1089
|
},
|
|
1090
|
+
computed: {
|
|
1091
|
+
canManipulate() {
|
|
1092
|
+
if (!this.roles) {
|
|
1093
|
+
return false;
|
|
1094
|
+
}
|
|
1095
|
+
return !this.roles.includes('readonly');
|
|
1096
|
+
}
|
|
1097
|
+
},
|
|
961
1098
|
methods: {
|
|
962
1099
|
cancelEdit() {
|
|
963
1100
|
this.changes = {};
|
|
@@ -993,6 +1130,9 @@ module.exports = app => app.component('document', {
|
|
|
993
1130
|
});
|
|
994
1131
|
this.$router.push({ path: `/model/${this.model}`});
|
|
995
1132
|
}
|
|
1133
|
+
},
|
|
1134
|
+
showClonedDocument(doc) {
|
|
1135
|
+
this.$router.push({ path: `/model/${this.model}/document/${doc._id}`});
|
|
996
1136
|
}
|
|
997
1137
|
}
|
|
998
1138
|
});
|
|
@@ -1648,7 +1788,7 @@ const limit = 20;
|
|
|
1648
1788
|
|
|
1649
1789
|
module.exports = app => app.component('models', {
|
|
1650
1790
|
template: template,
|
|
1651
|
-
props: ['model'],
|
|
1791
|
+
props: ['model', 'user', 'roles'],
|
|
1652
1792
|
data: () => ({
|
|
1653
1793
|
models: [],
|
|
1654
1794
|
currentModel: null,
|
|
@@ -1657,6 +1797,8 @@ module.exports = app => app.component('models', {
|
|
|
1657
1797
|
filteredPaths: [],
|
|
1658
1798
|
selectedPaths: [],
|
|
1659
1799
|
numDocuments: 0,
|
|
1800
|
+
mongoDBIndexes: [],
|
|
1801
|
+
schemaIndexes: [],
|
|
1660
1802
|
status: 'loading',
|
|
1661
1803
|
loadedAllDocs: false,
|
|
1662
1804
|
edittingDoc: null,
|
|
@@ -1666,6 +1808,7 @@ module.exports = app => app.component('models', {
|
|
|
1666
1808
|
shouldShowExportModal: false,
|
|
1667
1809
|
shouldShowCreateModal: false,
|
|
1668
1810
|
shouldShowFieldModal: false,
|
|
1811
|
+
shouldShowIndexModal: false,
|
|
1669
1812
|
shouldExport: {},
|
|
1670
1813
|
sortBy: {},
|
|
1671
1814
|
query: {},
|
|
@@ -1712,6 +1855,28 @@ module.exports = app => app.component('models', {
|
|
|
1712
1855
|
this.status = 'loaded';
|
|
1713
1856
|
},
|
|
1714
1857
|
methods: {
|
|
1858
|
+
clickFilter(path) {
|
|
1859
|
+
if (this.searchText) {
|
|
1860
|
+
if (this.searchText.endsWith('}')) {
|
|
1861
|
+
this.searchText = this.searchText.slice(0, -1) + `, ${path}: }`;
|
|
1862
|
+
} else {
|
|
1863
|
+
this.searchText += `, ${path}: }`;
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
} else {
|
|
1867
|
+
// If this.searchText is empty or undefined, initialize it with a new object
|
|
1868
|
+
this.searchText = `{ ${path}: }`;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
|
|
1872
|
+
this.$nextTick(() => {
|
|
1873
|
+
const input = this.$refs.searchInput;
|
|
1874
|
+
const cursorIndex = this.searchText.lastIndexOf(":") + 2; // Move cursor after ": "
|
|
1875
|
+
|
|
1876
|
+
input.focus();
|
|
1877
|
+
input.setSelectionRange(cursorIndex, cursorIndex);
|
|
1878
|
+
});
|
|
1879
|
+
},
|
|
1715
1880
|
async closeCreationModal() {
|
|
1716
1881
|
this.shouldShowCreateModal = false;
|
|
1717
1882
|
await this.getDocuments();
|
|
@@ -1778,6 +1943,21 @@ module.exports = app => app.component('models', {
|
|
|
1778
1943
|
}
|
|
1779
1944
|
await this.loadMoreDocuments();
|
|
1780
1945
|
},
|
|
1946
|
+
async openIndexModal() {
|
|
1947
|
+
this.shouldShowIndexModal = true;
|
|
1948
|
+
const { mongoDBIndexes, schemaIndexes } = await api.Model.getIndexes({ model: this.currentModel })
|
|
1949
|
+
this.mongoDBIndexes = mongoDBIndexes;
|
|
1950
|
+
this.schemaIndexes = schemaIndexes;
|
|
1951
|
+
},
|
|
1952
|
+
checkIndexLocation(indexName) {
|
|
1953
|
+
if (this.schemaIndexes.find(x => x.name == indexName) && this.mongoDBIndexes.find(x => x.name == indexName)) {
|
|
1954
|
+
return 'text-gray-500'
|
|
1955
|
+
} else if (this.schemaIndexes.find(x => x.name == indexName)) {
|
|
1956
|
+
return 'text-forest-green-500'
|
|
1957
|
+
} else {
|
|
1958
|
+
return 'text-valencia-500'
|
|
1959
|
+
}
|
|
1960
|
+
},
|
|
1781
1961
|
async getDocuments() {
|
|
1782
1962
|
const { docs, schemaPaths, numDocs } = await api.Model.getDocuments({
|
|
1783
1963
|
model: this.currentModel,
|
|
@@ -1804,7 +1984,6 @@ module.exports = app => app.component('models', {
|
|
|
1804
1984
|
for (const { path } of this.schemaPaths) {
|
|
1805
1985
|
this.shouldExport[path] = true;
|
|
1806
1986
|
}
|
|
1807
|
-
|
|
1808
1987
|
this.filteredPaths = [...this.schemaPaths];
|
|
1809
1988
|
this.selectedPaths = [...this.schemaPaths];
|
|
1810
1989
|
},
|
|
@@ -1985,7 +2164,7 @@ exports.hasAPIKey = client.hasAPIKey;
|
|
|
1985
2164
|
const api = __webpack_require__(/*! ../api */ "./frontend/src/api.js");
|
|
1986
2165
|
const mothership = __webpack_require__(/*! ../mothership */ "./frontend/src/mothership.js");
|
|
1987
2166
|
const template = __webpack_require__(/*! ./navbar.html */ "./frontend/src/navbar/navbar.html");
|
|
1988
|
-
const routes = __webpack_require__(/*! ../routes */ "./frontend/src/routes.js");
|
|
2167
|
+
const { routes, hasAccess } = __webpack_require__(/*! ../routes */ "./frontend/src/routes.js");
|
|
1989
2168
|
|
|
1990
2169
|
const appendCSS = __webpack_require__(/*! ../appendCSS */ "./frontend/src/appendCSS.js");
|
|
1991
2170
|
|
|
@@ -1996,6 +2175,15 @@ module.exports = app => app.component('navbar', {
|
|
|
1996
2175
|
props: ['user', 'roles'],
|
|
1997
2176
|
inject: ['state'],
|
|
1998
2177
|
data: () => ({ showFlyout: false }),
|
|
2178
|
+
mounted: function() {
|
|
2179
|
+
// Redirect to first allowed route if current route is not allowed
|
|
2180
|
+
if (!this.hasAccess(this.roles, this.$route.name)) {
|
|
2181
|
+
const firstAllowedRoute = this.allowedRoutes[0];
|
|
2182
|
+
if (firstAllowedRoute) {
|
|
2183
|
+
this.$router.push({ name: firstAllowedRoute.name });
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
},
|
|
1999
2187
|
computed: {
|
|
2000
2188
|
dashboardView() {
|
|
2001
2189
|
return routes.filter(x => x.name.startsWith('dashboard')).map(x => x.name).includes(this.$route.name)
|
|
@@ -2013,10 +2201,19 @@ module.exports = app => app.component('navbar', {
|
|
|
2013
2201
|
return mothership.hasAPIKey;
|
|
2014
2202
|
},
|
|
2015
2203
|
canViewTeam() {
|
|
2016
|
-
return this.
|
|
2204
|
+
return this.hasAccess(this.roles, 'team');
|
|
2205
|
+
},
|
|
2206
|
+
allowedRoutes() {
|
|
2207
|
+
return routes.filter(route => this.hasAccess(this.roles, route.name));
|
|
2208
|
+
},
|
|
2209
|
+
defaultRoute() {
|
|
2210
|
+
return this.allowedRoutes[0]?.name || 'dashboards';
|
|
2017
2211
|
}
|
|
2018
2212
|
},
|
|
2019
2213
|
methods: {
|
|
2214
|
+
hasAccess(roles, routeName) {
|
|
2215
|
+
return hasAccess(roles, routeName);
|
|
2216
|
+
},
|
|
2020
2217
|
async loginWithGithub() {
|
|
2021
2218
|
const { url } = await mothership.githubLogin();
|
|
2022
2219
|
window.location.href = url;
|
|
@@ -2062,38 +2259,76 @@ module.exports = app => app.component('navbar', {
|
|
|
2062
2259
|
"use strict";
|
|
2063
2260
|
|
|
2064
2261
|
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2262
|
+
// Role-based access control configuration
|
|
2263
|
+
const roleAccess = {
|
|
2264
|
+
owner: ['root', 'model', 'document', 'dashboards', 'dashboard', 'team'],
|
|
2265
|
+
admin: ['root', 'model', 'document', 'dashboards', 'dashboard', 'team'],
|
|
2266
|
+
member: ['root', 'model', 'document', 'dashboards', 'dashboard'],
|
|
2267
|
+
readonly: ['root', 'model', 'document'],
|
|
2268
|
+
dashboards: ['dashboards', 'dashboard']
|
|
2269
|
+
};
|
|
2270
|
+
|
|
2271
|
+
// Helper function to check if a role has access to a route
|
|
2272
|
+
function hasAccess(roles, routeName) {
|
|
2273
|
+
// change to true for local development
|
|
2274
|
+
if (!roles) return false;
|
|
2275
|
+
return roles.some(role => roleAccess[role]?.includes(routeName));
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
module.exports = {
|
|
2279
|
+
routes: [
|
|
2280
|
+
{
|
|
2281
|
+
path: '/',
|
|
2282
|
+
name: 'root',
|
|
2283
|
+
component: 'models',
|
|
2284
|
+
meta: {
|
|
2285
|
+
authorized: true
|
|
2286
|
+
}
|
|
2287
|
+
},
|
|
2288
|
+
{
|
|
2289
|
+
path: '/model/:model',
|
|
2290
|
+
name: 'model',
|
|
2291
|
+
component: 'models',
|
|
2292
|
+
meta: {
|
|
2293
|
+
authorized: true
|
|
2294
|
+
}
|
|
2295
|
+
},
|
|
2296
|
+
{
|
|
2297
|
+
path: '/model/:model/document/:documentId',
|
|
2298
|
+
name: 'document',
|
|
2299
|
+
component: 'document',
|
|
2300
|
+
meta: {
|
|
2301
|
+
authorized: true
|
|
2302
|
+
}
|
|
2303
|
+
},
|
|
2304
|
+
{
|
|
2305
|
+
path: '/dashboards',
|
|
2306
|
+
name: 'dashboards',
|
|
2307
|
+
component: 'dashboards',
|
|
2308
|
+
meta: {
|
|
2309
|
+
authorized: true
|
|
2310
|
+
}
|
|
2311
|
+
},
|
|
2312
|
+
{
|
|
2313
|
+
path: '/dashboard/:dashboardId',
|
|
2314
|
+
name: 'dashboard',
|
|
2315
|
+
component: 'dashboard',
|
|
2316
|
+
meta: {
|
|
2317
|
+
authorized: true
|
|
2318
|
+
}
|
|
2319
|
+
},
|
|
2320
|
+
{
|
|
2321
|
+
path: '/team',
|
|
2322
|
+
name: 'team',
|
|
2323
|
+
component: 'team',
|
|
2324
|
+
meta: {
|
|
2325
|
+
authorized: true
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
],
|
|
2329
|
+
roleAccess,
|
|
2330
|
+
hasAccess
|
|
2331
|
+
};
|
|
2097
2332
|
|
|
2098
2333
|
|
|
2099
2334
|
/***/ }),
|
|
@@ -2831,6 +3066,28 @@ module.exports = "<button v-bind=\"attrsToBind\" :disabled=\"isDisabled\" @click
|
|
|
2831
3066
|
|
|
2832
3067
|
/***/ }),
|
|
2833
3068
|
|
|
3069
|
+
/***/ "./frontend/src/clone-document/clone-document.css":
|
|
3070
|
+
/*!********************************************************!*\
|
|
3071
|
+
!*** ./frontend/src/clone-document/clone-document.css ***!
|
|
3072
|
+
\********************************************************/
|
|
3073
|
+
/***/ ((module) => {
|
|
3074
|
+
|
|
3075
|
+
"use strict";
|
|
3076
|
+
module.exports = "";
|
|
3077
|
+
|
|
3078
|
+
/***/ }),
|
|
3079
|
+
|
|
3080
|
+
/***/ "./frontend/src/clone-document/clone-document.html":
|
|
3081
|
+
/*!*********************************************************!*\
|
|
3082
|
+
!*** ./frontend/src/clone-document/clone-document.html ***!
|
|
3083
|
+
\*********************************************************/
|
|
3084
|
+
/***/ ((module) => {
|
|
3085
|
+
|
|
3086
|
+
"use strict";
|
|
3087
|
+
module.exports = "<div>\n <div class=\"mb-2\">\n <textarea class=\"border border-gray-200 p-2 h-[300px] w-full\" ref=\"codeEditor\"></textarea>\n </div>\n <button @click=\"cloneDocument()\" 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\">Submit</button>\n <div v-if=\"errors.length > 0\" class=\"rounded-md bg-red-50 p-4 mt-1\">\n <div class=\"flex\">\n <div class=\"flex-shrink-0\">\n <svg class=\"h-5 w-5 text-red-400\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\" clip-rule=\"evenodd\" />\n </svg>\n </div>\n <div class=\"ml-3\">\n <h3 class=\"text-sm font-medium text-red-800\">There were {{errors.length}} errors with your submission</h3>\n <div class=\"mt-2 text-sm text-red-700\">\n <ul role=\"list\" class=\"list-disc space-y-1 pl-5\">\n <li v-for=\"error in errors\">\n {{error}}\n </li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n </div>\n ";
|
|
3088
|
+
|
|
3089
|
+
/***/ }),
|
|
3090
|
+
|
|
2834
3091
|
/***/ "./frontend/src/create-dashboard/create-dashboard.html":
|
|
2835
3092
|
/*!*************************************************************!*\
|
|
2836
3093
|
!*** ./frontend/src/create-dashboard/create-dashboard.html ***!
|
|
@@ -3058,7 +3315,7 @@ module.exports = ".document {\n max-width: 1200px;\n margin-left: auto;\n mar
|
|
|
3058
3315
|
/***/ ((module) => {
|
|
3059
3316
|
|
|
3060
3317
|
"use strict";
|
|
3061
|
-
module.exports = "<div class=\"document\">\n <div class=\"document-menu\">\n <div class=\"left\">\n <button\n @click=\"$router.push('/model/' + this.model)\"\n class=\"rounded-md bg-gray-400 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-slate-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-600\">\n ‹ Back\n </button>\n </div>\n\n <div class=\"right\">\n <button\n v-if=\"!editting\"\n @click=\"editting = true\"\n type=\"button\"\n 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\">\n <img src=\"images/edit.svg\" class=\"inline\" /> Edit\n </button>\n <button\n v-if=\"editting\"\n @click=\"editting = false\"\n type=\"button\"\n class=\"rounded-md bg-slate-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-slate-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-600\">\n × Cancel\n </button>\n <button\n v-if=\"editting\"\n @click=\"shouldShowConfirmModal=true;\"\n type=\"button\"\n 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\">\n <img src=\"images/save.svg\" class=\"inline\" /> Save\n </button>\n <button\n @click=\"shouldShowDeleteModal=true;\"\n type=\"button\"\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\">\n <img src=\"images/delete.svg\" class=\"inline\" /> Delete\n </button>\n </div>\n </div>\n <div v-if=\"status === 'loaded'\">\n <document-details\n :document=\"document\"\n :schemaPaths=\"schemaPaths\"\n :editting=\"editting\"\n :changes=\"changes\"\n :invalid=\"invalid\"></document-details>\n <modal v-if=\"shouldShowConfirmModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowConfirmModal = false;\">×</div>\n <confirm-changes @close=\"shouldShowConfirmModal = false;\" @save=\"save\" :value=\"changes\"></confirm-changes>\n </template>\n </modal>\n <modal v-if=\"shouldShowDeleteModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowConfirmModal = false;\">×</div>\n <confirm-delete @close=\"shouldShowConfirmModal = false;\" @remove=\"remove\" :value=\"document\"></confirm-delete>\n </template>\n </modal>\n </div>\n</div>\n";
|
|
3318
|
+
module.exports = "<div class=\"document\">\n <div class=\"document-menu\">\n <div class=\"left\">\n <button\n @click=\"$router.push('/model/' + this.model)\"\n class=\"rounded-md bg-gray-400 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-slate-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-600\">\n ‹ Back\n </button>\n </div>\n\n <div class=\"right\">\n <button\n v-if=\"!editting\"\n @click=\"editting = true\"\n :disabled=\"!canManipulate\"\n :class=\"{'cursor-not-allowed opacity-50': !canManipulate}\"\n type=\"button\"\n 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\">\n <img src=\"images/edit.svg\" class=\"inline\" /> Edit\n </button>\n <button\n v-if=\"editting\"\n @click=\"editting = false\"\n type=\"button\"\n class=\"rounded-md bg-slate-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-slate-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-600\">\n × Cancel\n </button>\n <button\n v-if=\"editting\"\n :disabled=\"!canManipulate\"\n :class=\"{'cursor-not-allowed opacity-50': !canManipulate}\"\n @click=\"shouldShowConfirmModal=true;\"\n type=\"button\"\n 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\">\n <img src=\"images/save.svg\" class=\"inline\" /> Save\n </button>\n <button\n @click=\"shouldShowDeleteModal=true;\"\n :disabled=\"!canManipulate\"\n :class=\"{'cursor-not-allowed opacity-50': !canManipulate}\"\n type=\"button\"\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\">\n <img src=\"images/delete.svg\" class=\"inline\" /> Delete\n </button>\n <button\n @click=\"shouldShowCloneModal=true;\"\n :disabled=\"!canManipulate\"\n :class=\"{'cursor-not-allowed opacity-50': !canManipulate}\"\n type=\"button\"\n class=\"rounded-md bg-pink-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\">\n <img src=\"images/duplicate.svg\" class=\"inline\" /> Clone\n </button>\n </div>\n </div>\n <div v-if=\"status === 'loaded'\">\n <document-details\n :document=\"document\"\n :schemaPaths=\"schemaPaths\"\n :editting=\"editting\"\n :changes=\"changes\"\n :invalid=\"invalid\"></document-details>\n <modal v-if=\"shouldShowConfirmModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowConfirmModal = false;\">×</div>\n <confirm-changes @close=\"shouldShowConfirmModal = false;\" @save=\"save\" :value=\"changes\"></confirm-changes>\n </template>\n </modal>\n <modal v-if=\"shouldShowDeleteModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowConfirmModal = false;\">×</div>\n <confirm-delete @close=\"shouldShowConfirmModal = false;\" @remove=\"remove\" :value=\"document\"></confirm-delete>\n </template>\n </modal>\n <modal v-if=\"shouldShowCloneModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowCloneModal = false;\">×</div>\n <clone-document :currentModel=\"model\" :doc=\"document\" :schemaPaths=\"schemaPaths\" @close=\"showClonedDocument\"></clone-document>\n </template>\n </modal>\n </div>\n</div>\n";
|
|
3062
3319
|
|
|
3063
3320
|
/***/ }),
|
|
3064
3321
|
|
|
@@ -3146,7 +3403,7 @@ module.exports = "";
|
|
|
3146
3403
|
/***/ ((module) => {
|
|
3147
3404
|
|
|
3148
3405
|
"use strict";
|
|
3149
|
-
module.exports = "<div class=\"export-query-results\">\n <h2>Export as CSV</h2>\n <div>\n Choose fields to export\n </div>\n <div v-for=\"schemaPath in schemaPaths\">\n <input type=\"checkbox\" v-model=\"shouldExport[schemaPath.path]\">\n <
|
|
3406
|
+
module.exports = "<div class=\"export-query-results\">\n <h2>Export as CSV</h2>\n <div>\n Choose fields to export\n </div>\n <div v-for=\"(schemaPath,index) in schemaPaths\" class=\"w-5 flex items-center\">\n <input type=\"checkbox\" class=\"mt-0 h-4 w-4 rounded border-gray-300 text-sky-600 focus:ring-sky-600 accent-sky-600\" v-model=\"shouldExport[schemaPath.path]\" :id=\"'schemaPath.path'+index\">\n <div class=\"ml-2 text-gray-700 grow shrink text-left\">\n <label :for=\"'schemaPath.path'+index\">{{schemaPath.path}}</label>\n </div>\n </div>\n <async-button 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\" @click=\"exportQueryResults\">Export</async-button>\n</div>";
|
|
3150
3407
|
|
|
3151
3408
|
/***/ }),
|
|
3152
3409
|
|
|
@@ -3322,7 +3579,7 @@ module.exports = ".models {\n position: relative;\n display: flex;\n flex-dir
|
|
|
3322
3579
|
/***/ ((module) => {
|
|
3323
3580
|
|
|
3324
3581
|
"use strict";
|
|
3325
|
-
module.exports = "<div class=\"models\">\n <div>\n <div class=\"flex grow flex-col gap-y-5 overflow-auto border-r border-gray-200 bg-white px-2 h-[calc(100vh-55px)] w-48\">\n <div class=\"flex font-bold font-xl mt-4 pl-2\">\n Models\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 </div>\n\n </div>\n <div class=\"documents\" ref=\"documentsList\">\n <div class=\"relative h-[42px]\">\n <div class=\"documents-menu\">\n <div class=\"flex flex-row items-center w-full gap-2\">\n <form @submit.prevent=\"search\" class=\"flex-grow m-0\">\n <input class=\"w-full 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 or text\" v-model=\"searchText\" />\n </form>\n <div>\n <span v-if=\"status === 'loading'\">Loading ...</span>\n <span v-if=\"status === 'loaded'\">{{numDocuments === 1 ? numDocuments+ ' document' : numDocuments + ' documents'}}</span>\n </div>\n <button\n @click=\"shouldShowExportModal = true\"\n type=\"button\"\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=\"shouldShowCreateModal = true;\"\n type=\"button\"\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 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\">\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=\"$router.push('/model/' + currentModel + '/document/' + document._id)\" :key=\"document._id\">\n <td v-for=\"schemaPath in filteredPaths\">\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=\"$router.push('/model/' + currentModel + '/document/' + document._id)\" :key=\"document._id\">\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
|
|
3582
|
+
module.exports = "<div class=\"models\">\n <div>\n <div class=\"flex grow flex-col gap-y-5 overflow-auto border-r border-gray-200 bg-white px-2 h-[calc(100vh-55px)] w-48\">\n <div class=\"flex font-bold font-xl mt-4 pl-2\">\n Models\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 </div>\n\n </div>\n <div class=\"documents\" ref=\"documentsList\">\n <div class=\"relative h-[42px]\">\n <div class=\"documents-menu\">\n <div class=\"flex flex-row items-center w-full gap-2\">\n <form @submit.prevent=\"search\" class=\"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 or text\" v-model=\"searchText\" />\n </form>\n <div>\n <span v-if=\"status === 'loading'\">Loading ...</span>\n <span v-if=\"status === 'loaded'\">{{numDocuments === 1 ? numDocuments+ ' document' : numDocuments + ' documents'}}</span>\n </div>\n <button\n @click=\"shouldShowExportModal = true\"\n type=\"button\"\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=\"openIndexModal\"\n type=\"button\"\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 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 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=\"$router.push('/model/' + currentModel + '/document/' + document._id)\" :key=\"document._id\">\n <td v-for=\"schemaPath in filteredPaths\">\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=\"$router.push('/model/' + currentModel + '/document/' + document._id)\" :key=\"document._id\">\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 :filter=\"filter\"\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 <button type=\"submit\" @click=\"dropIndex()\" disabled=\"true\" 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\">Drop</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=\"submit\" @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=\"submit\" @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=\"submit\" @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</div>\n";
|
|
3326
3583
|
|
|
3327
3584
|
/***/ }),
|
|
3328
3585
|
|
|
@@ -3344,7 +3601,7 @@ module.exports = ".navbar {\n width: 100%;\n background-color: #eee;\n}\n\n.ac
|
|
|
3344
3601
|
/***/ ((module) => {
|
|
3345
3602
|
|
|
3346
3603
|
"use strict";
|
|
3347
|
-
module.exports = "<div class=\"navbar\">\n <div class=\"nav-left flex items-center gap-4 h-full\">\n <router-link to=\"
|
|
3604
|
+
module.exports = "<div class=\"navbar\">\n <div class=\"nav-left flex items-center gap-4 h-full\">\n <router-link :to=\"{ name: defaultRoute }\">\n <img src=\"images/logo.svg\" alt=\"Mongoose Studio Logo\" />\n </router-link>\n <div v-if=\"!!state.nodeEnv\" class=\"inline-flex items-center rounded-md px-2 py-1 text-sm font-medium text-gray-900\" :class=\"warnEnv ? 'bg-red-300' : 'bg-yellow-300'\">\n {{state.nodeEnv}}\n </div>\n </div>\n <div class=\"nav-right h-full\">\n <div class=\"sm:ml-6 sm:flex sm:space-x-8 h-full\">\n <a v-if=\"hasAccess(roles, 'root')\"\n href=\"#/\"\n class=\"inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium\"\n :class=\"documentView ? 'text-gray-900 border-ultramarine-500' : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700'\">Documents</a>\n <a v-if=\"hasAccess(roles, 'dashboards')\"\n href=\"#/dashboards\"\n class=\"inline-flex items-center border-b-2 px-1 pt-1 text-sm font-medium\"\n :class=\"dashboardView ? 'text-gray-900 border-ultramarine-500' : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700'\">Dashboards</a>\n\n <div class=\"h-full flex items-center\" v-if=\"!user && hasAPIKey\">\n <button\n type=\"button\"\n @click=\"loginWithGithub\"\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 Login\n </button>\n </div>\n <div v-if=\"user && hasAPIKey\" class=\"h-full flex items-center relative\" v-clickOutside=\"hideFlyout\">\n <div>\n <button type=\"button\" @click=\"showFlyout = !showFlyout\" class=\"relative flex rounded-full bg-gray-800 text-sm focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800\" id=\"user-menu-button\" aria-expanded=\"false\" aria-haspopup=\"true\">\n <span class=\"absolute -inset-1.5\"></span>\n <span class=\"sr-only\">Open user menu</span>\n <img class=\"size-8 rounded-full\" :src=\"user.picture\" alt=\"\">\n </button>\n </div>\n\n <div v-if=\"showFlyout\" class=\"absolute right-0 z-10 top-[90%] w-48 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black/5 focus:outline-none\" role=\"menu\" aria-orientation=\"vertical\" aria-labelledby=\"user-menu-button\" tabindex=\"-1\">\n <router-link to=\"/team\" v-if=\"hasAccess(roles, 'team')\" @click=\"showFlyout = false\" class=\"cursor-pointer block px-4 py-2 text-sm text-gray-700 hover:bg-ultramarine-200\" role=\"menuitem\" tabindex=\"-1\" id=\"user-menu-item-2\">Team</router-link>\n <span @click=\"logout\" class=\"cursor-pointer block px-4 py-2 text-sm text-gray-700 hover:bg-ultramarine-200\" role=\"menuitem\" tabindex=\"-1\" id=\"user-menu-item-2\">Sign out</span>\n </div>\n </div>\n\n </div>\n </div>\n <div style=\"clear: both\"></div>\n</div>\n";
|
|
3348
3605
|
|
|
3349
3606
|
/***/ }),
|
|
3350
3607
|
|
|
@@ -11207,6 +11464,7 @@ const app = Vue.createApp({
|
|
|
11207
11464
|
});
|
|
11208
11465
|
|
|
11209
11466
|
__webpack_require__(/*! ./async-button/async-button */ "./frontend/src/async-button/async-button.js")(app);
|
|
11467
|
+
__webpack_require__(/*! ./clone-document/clone-document */ "./frontend/src/clone-document/clone-document.js")(app);
|
|
11210
11468
|
__webpack_require__(/*! ./create-dashboard/create-dashboard */ "./frontend/src/create-dashboard/create-dashboard.js")(app);
|
|
11211
11469
|
__webpack_require__(/*! ./create-document/create-document */ "./frontend/src/create-document/create-document.js")(app);
|
|
11212
11470
|
__webpack_require__(/*! ./dashboards/dashboards */ "./frontend/src/dashboards/dashboards.js")(app);
|
|
@@ -11252,7 +11510,7 @@ app.component('app-component', {
|
|
|
11252
11510
|
<div v-else-if="!hasAPIKey || user">
|
|
11253
11511
|
<navbar :user="user" :roles="roles" />
|
|
11254
11512
|
<div class="view">
|
|
11255
|
-
<router-view :key="$route.fullPath" />
|
|
11513
|
+
<router-view :key="$route.fullPath" :user="user" :roles="roles" />
|
|
11256
11514
|
</div>
|
|
11257
11515
|
</div>
|
|
11258
11516
|
</div>
|
|
@@ -11272,6 +11530,7 @@ app.component('app-component', {
|
|
|
11272
11530
|
},
|
|
11273
11531
|
async mounted() {
|
|
11274
11532
|
window.$router = this.$router;
|
|
11533
|
+
window.state = this;
|
|
11275
11534
|
|
|
11276
11535
|
if (mothership.hasAPIKey) {
|
|
11277
11536
|
const href = window.location.href;
|
|
@@ -11329,7 +11588,7 @@ app.component('app-component', {
|
|
|
11329
11588
|
}
|
|
11330
11589
|
});
|
|
11331
11590
|
|
|
11332
|
-
const routes = __webpack_require__(/*! ./routes */ "./frontend/src/routes.js");
|
|
11591
|
+
const { routes } = __webpack_require__(/*! ./routes */ "./frontend/src/routes.js");
|
|
11333
11592
|
const router = VueRouter.createRouter({
|
|
11334
11593
|
history: VueRouter.createWebHashHistory(),
|
|
11335
11594
|
routes: routes.map(route => ({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#FFFFFF"><path d="M560-320h80v-120h120v-80H640v-120h-80v120H440v80h120v120ZM240-140Q131-178 65.5-271.5T0-480q0-115 65.5-208.5T240-820v88q-74 35-117 103T80-480q0 81 43 149t117 103v88Zm360 20q-75 0-140.5-28.5t-114-77q-48.5-48.5-77-114T240-480q0-75 28.5-140.5t77-114q48.5-48.5 114-77T600-840q75 0 140.5 28.5t114 77q48.5 48.5 77 114T960-480q0 75-28.5 140.5t-77 114q-48.5 48.5-114 77T600-120Zm0-360Zm0 280q117 0 198.5-81.5T880-480q0-117-81.5-198.5T600-760q-117 0-198.5 81.5T320-480q0 117 81.5 198.5T600-200Z"/></svg>
|