@mongoosejs/studio 0.0.101 → 0.0.102
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/Dashboard/getDashboard.js +39 -9
- package/backend/actions/Model/getDocuments.js +7 -2
- package/frontend/public/app.js +55 -10
- package/frontend/public/tw.css +7 -2
- package/frontend/src/chat/chat-message-script/chat-message-script.html +1 -1
- package/frontend/src/dashboard/dashboard.html +32 -6
- package/frontend/src/dashboard/dashboard.js +24 -3
- package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.html +2 -2
- package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.js +1 -1
- package/frontend/src/dashboard-result/dashboard-result.html +3 -0
- package/frontend/src/dashboard-result/dashboard-result.js +1 -1
- package/frontend/src/format.js +9 -0
- package/frontend/src/index.js +2 -0
- package/package.json +1 -1
|
@@ -32,24 +32,27 @@ module.exports = ({ db }) => async function getDashboard(params) {
|
|
|
32
32
|
const dashboard = await Dashboard.findOne({ _id: dashboardId });
|
|
33
33
|
if (evaluate) {
|
|
34
34
|
let result = null;
|
|
35
|
-
const startExec =
|
|
35
|
+
const startExec = startDashboardEvaluate(dashboardId, $workspaceId, authorization);
|
|
36
|
+
// Avoid unhandled promise rejection since we handle the promise later.
|
|
37
|
+
startExec.catch(() => {});
|
|
36
38
|
try {
|
|
37
39
|
result = await dashboard.evaluate();
|
|
38
40
|
} catch (error) {
|
|
39
41
|
return { dashboard, error: { message: error.message } };
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
await startExec.then(({ dashboardResult }) => {
|
|
44
|
+
const { dashboardResult } = await startExec.then(({ dashboardResult }) => {
|
|
43
45
|
if (!dashboardResult) {
|
|
44
46
|
return;
|
|
45
47
|
}
|
|
46
48
|
return completeDashboardEvaluate(dashboardResult._id, $workspaceId, authorization, result);
|
|
47
49
|
});
|
|
48
50
|
|
|
49
|
-
return { dashboard,
|
|
51
|
+
return { dashboard, dashboardResult };
|
|
52
|
+
} else {
|
|
53
|
+
const { dashboardResults } = await getDashboardResults(dashboardId, $workspaceId, authorization);
|
|
54
|
+
return { dashboard, dashboardResults };
|
|
50
55
|
}
|
|
51
|
-
|
|
52
|
-
return { dashboard };
|
|
53
56
|
};
|
|
54
57
|
|
|
55
58
|
async function completeDashboardEvaluate(dashboardResultId, workspaceId, authorization, result) {
|
|
@@ -60,7 +63,7 @@ async function completeDashboardEvaluate(dashboardResultId, workspaceId, authori
|
|
|
60
63
|
if (authorization) {
|
|
61
64
|
headers.Authorization = authorization;
|
|
62
65
|
}
|
|
63
|
-
const response = await fetch('
|
|
66
|
+
const response = await fetch('https://mongoose-js.netlify.app/.netlify/functions/completeDashboardEvaluate', {
|
|
64
67
|
method: 'POST',
|
|
65
68
|
headers,
|
|
66
69
|
body: JSON.stringify({
|
|
@@ -81,7 +84,7 @@ async function completeDashboardEvaluate(dashboardResultId, workspaceId, authori
|
|
|
81
84
|
return await response.json();
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
async function
|
|
87
|
+
async function startDashboardEvaluate(dashboardId, workspaceId, authorization) {
|
|
85
88
|
if (!workspaceId) {
|
|
86
89
|
return {};
|
|
87
90
|
}
|
|
@@ -89,7 +92,7 @@ async function startDashboardExec(dashboardId, workspaceId, authorization) {
|
|
|
89
92
|
if (authorization) {
|
|
90
93
|
headers.Authorization = authorization;
|
|
91
94
|
}
|
|
92
|
-
const response = await fetch('
|
|
95
|
+
const response = await fetch('https://mongoose-js.netlify.app/.netlify/functions/startDashboardEvaluate', {
|
|
93
96
|
method: 'POST',
|
|
94
97
|
headers,
|
|
95
98
|
body: JSON.stringify({
|
|
@@ -100,7 +103,34 @@ async function startDashboardExec(dashboardId, workspaceId, authorization) {
|
|
|
100
103
|
}).then(response => {
|
|
101
104
|
if (response.status < 200 || response.status >= 400) {
|
|
102
105
|
return response.json().then(data => {
|
|
103
|
-
throw new Error(`
|
|
106
|
+
throw new Error(`startDashboardEvaluate error: ${data.message}`);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return response;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return await response.json();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function getDashboardResults(dashboardId, workspaceId, authorization) {
|
|
116
|
+
if (!workspaceId) {
|
|
117
|
+
return {};
|
|
118
|
+
}
|
|
119
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
120
|
+
if (authorization) {
|
|
121
|
+
headers.Authorization = authorization;
|
|
122
|
+
}
|
|
123
|
+
const response = await fetch('https://mongoose-js.netlify.app/.netlify/functions/getDashboardResults', {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
headers,
|
|
126
|
+
body: JSON.stringify({
|
|
127
|
+
dashboardId,
|
|
128
|
+
workspaceId
|
|
129
|
+
})
|
|
130
|
+
}).then(response => {
|
|
131
|
+
if (response.status < 200 || response.status >= 400) {
|
|
132
|
+
return response.json().then(data => {
|
|
133
|
+
throw new Error(`getDashboardResults error: ${data.message}`);
|
|
104
134
|
});
|
|
105
135
|
}
|
|
106
136
|
return response;
|
|
@@ -52,11 +52,16 @@ module.exports = ({ db }) => async function getDocuments(params) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
const hasSort = typeof sort === 'object' && sort != null && Object.keys(sort).length > 0;
|
|
55
|
-
const
|
|
55
|
+
const cursor = await Model.
|
|
56
56
|
find(filter == null ? {} : filter).
|
|
57
57
|
limit(limit).
|
|
58
58
|
skip(skip).
|
|
59
|
-
sort(hasSort ? sort : { _id: -1 })
|
|
59
|
+
sort(hasSort ? sort : { _id: -1 }).
|
|
60
|
+
cursor();
|
|
61
|
+
const docs = [];
|
|
62
|
+
for (let doc = await cursor.next(); doc != null; doc = await cursor.next()) {
|
|
63
|
+
docs.push(doc);
|
|
64
|
+
}
|
|
60
65
|
|
|
61
66
|
const schemaPaths = {};
|
|
62
67
|
for (const path of Object.keys(Model.schema.paths)) {
|
package/frontend/public/app.js
CHANGED
|
@@ -783,7 +783,7 @@ const template = __webpack_require__(/*! ./dashboard-chart.html */ "./frontend/s
|
|
|
783
783
|
|
|
784
784
|
module.exports = app => app.component('dashboard-chart', {
|
|
785
785
|
template: template,
|
|
786
|
-
props: ['value'],
|
|
786
|
+
props: ['value', 'responsive'],
|
|
787
787
|
mounted() {
|
|
788
788
|
const ctx = this.$refs.chart.getContext('2d');
|
|
789
789
|
const chart = new Chart(ctx, this.value.$chart);
|
|
@@ -892,7 +892,7 @@ const template = __webpack_require__(/*! ./dashboard-result.html */ "./frontend/
|
|
|
892
892
|
|
|
893
893
|
module.exports = app => app.component('dashboard-result', {
|
|
894
894
|
template: template,
|
|
895
|
-
props: ['result'],
|
|
895
|
+
props: ['result', 'finishedEvaluatingAt'],
|
|
896
896
|
mounted: async function() {
|
|
897
897
|
},
|
|
898
898
|
methods: {
|
|
@@ -961,7 +961,7 @@ module.exports = app => app.component('dashboard', {
|
|
|
961
961
|
description: '',
|
|
962
962
|
showEditor: false,
|
|
963
963
|
dashboard: null,
|
|
964
|
-
|
|
964
|
+
dashboardResults: [],
|
|
965
965
|
errorMessage: null
|
|
966
966
|
};
|
|
967
967
|
},
|
|
@@ -978,11 +978,32 @@ module.exports = app => app.component('dashboard', {
|
|
|
978
978
|
} else {
|
|
979
979
|
this.errorMessage = update.error.message;
|
|
980
980
|
}
|
|
981
|
+
},
|
|
982
|
+
async evaluateDashboard() {
|
|
983
|
+
this.status = 'evaluating';
|
|
984
|
+
try {
|
|
985
|
+
const { dashboard, dashboardResult, error } = await api.Dashboard.getDashboard({ dashboardId: this.dashboardId, evaluate: true });
|
|
986
|
+
this.dashboard = dashboard;
|
|
987
|
+
if (error) {
|
|
988
|
+
this.errorMessage = error.message;
|
|
989
|
+
}
|
|
990
|
+
this.code = this.dashboard.code;
|
|
991
|
+
this.title = this.dashboard.title;
|
|
992
|
+
this.description = this.dashboard.description ?? '';
|
|
993
|
+
this.dashboardResults.unshift(dashboardResult);
|
|
994
|
+
} finally {
|
|
995
|
+
this.status = 'loaded';
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
},
|
|
999
|
+
computed: {
|
|
1000
|
+
dashboardResult() {
|
|
1001
|
+
return this.dashboardResults.length > 0 ? this.dashboardResults[0] : null;
|
|
981
1002
|
}
|
|
982
1003
|
},
|
|
983
1004
|
mounted: async function() {
|
|
984
1005
|
this.showEditor = this.$route.query.edit;
|
|
985
|
-
const { dashboard,
|
|
1006
|
+
const { dashboard, dashboardResults, error } = await api.Dashboard.getDashboard({ dashboardId: this.dashboardId, evaluate: false });
|
|
986
1007
|
if (!dashboard) {
|
|
987
1008
|
return;
|
|
988
1009
|
}
|
|
@@ -993,7 +1014,7 @@ module.exports = app => app.component('dashboard', {
|
|
|
993
1014
|
this.code = this.dashboard.code;
|
|
994
1015
|
this.title = this.dashboard.title;
|
|
995
1016
|
this.description = this.dashboard.description ?? '';
|
|
996
|
-
this.
|
|
1017
|
+
this.dashboardResults = dashboardResults;
|
|
997
1018
|
this.status = 'loaded';
|
|
998
1019
|
}
|
|
999
1020
|
});
|
|
@@ -1756,6 +1777,26 @@ module.exports = app => app.component('export-query-results', {
|
|
|
1756
1777
|
}
|
|
1757
1778
|
});
|
|
1758
1779
|
|
|
1780
|
+
/***/ }),
|
|
1781
|
+
|
|
1782
|
+
/***/ "./frontend/src/format.js":
|
|
1783
|
+
/*!********************************!*\
|
|
1784
|
+
!*** ./frontend/src/format.js ***!
|
|
1785
|
+
\********************************/
|
|
1786
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
1787
|
+
|
|
1788
|
+
"use strict";
|
|
1789
|
+
|
|
1790
|
+
|
|
1791
|
+
exports.isoToLongDateTime = function isoToLongDateTime(str) {
|
|
1792
|
+
if (!str) {
|
|
1793
|
+
return 'Unknown';
|
|
1794
|
+
}
|
|
1795
|
+
const date = new Date(str);
|
|
1796
|
+
return date.toLocaleString('en-US', { month: 'short', day: '2-digit', year: 'numeric', hour: 'numeric', minute: 'numeric' });
|
|
1797
|
+
};
|
|
1798
|
+
|
|
1799
|
+
|
|
1759
1800
|
/***/ }),
|
|
1760
1801
|
|
|
1761
1802
|
/***/ "./frontend/src/index.js":
|
|
@@ -1775,6 +1816,7 @@ const { version } = __webpack_require__(/*! ../../package.json */ "./package.jso
|
|
|
1775
1816
|
console.log(`Mongoose Studio Version ${version}`);
|
|
1776
1817
|
|
|
1777
1818
|
const api = __webpack_require__(/*! ./api */ "./frontend/src/api.js");
|
|
1819
|
+
const format = __webpack_require__(/*! ./format */ "./frontend/src/format.js");
|
|
1778
1820
|
const mothership = __webpack_require__(/*! ./mothership */ "./frontend/src/mothership.js");
|
|
1779
1821
|
const { routes } = __webpack_require__(/*! ./routes */ "./frontend/src/routes.js");
|
|
1780
1822
|
const vanillatoasts = __webpack_require__(/*! vanillatoasts */ "./node_modules/vanillatoasts/vanillatoasts.js");
|
|
@@ -1912,6 +1954,7 @@ router.beforeEach((to, from, next) => {
|
|
|
1912
1954
|
}
|
|
1913
1955
|
});
|
|
1914
1956
|
|
|
1957
|
+
app.config.globalProperties = { format };
|
|
1915
1958
|
app.use(router);
|
|
1916
1959
|
|
|
1917
1960
|
app.mount('#content');
|
|
@@ -3220,6 +3263,8 @@ var map = {
|
|
|
3220
3263
|
"./export-query-results/export-query-results.css": "./frontend/src/export-query-results/export-query-results.css",
|
|
3221
3264
|
"./export-query-results/export-query-results.html": "./frontend/src/export-query-results/export-query-results.html",
|
|
3222
3265
|
"./export-query-results/export-query-results.js": "./frontend/src/export-query-results/export-query-results.js",
|
|
3266
|
+
"./format": "./frontend/src/format.js",
|
|
3267
|
+
"./format.js": "./frontend/src/format.js",
|
|
3223
3268
|
"./index": "./frontend/src/index.js",
|
|
3224
3269
|
"./index.js": "./frontend/src/index.js",
|
|
3225
3270
|
"./list-array/list-array": "./frontend/src/list-array/list-array.js",
|
|
@@ -3917,7 +3962,7 @@ module.exports = "<button v-bind=\"attrsToBind\" :disabled=\"isDisabled\" @click
|
|
|
3917
3962
|
/***/ ((module) => {
|
|
3918
3963
|
|
|
3919
3964
|
"use strict";
|
|
3920
|
-
module.exports = "<div class=\"relative border rounded bg-gray-100 text-black text-sm overflow-hidden\">\n <div class=\"flex border-b pt-[1px] text-xs font-medium bg-gray-200\">\n <button\n class=\"px-3 py-1 border-r border-gray-300 hover:bg-green-300\"\n :class=\"{'bg-gray-300': activeTab === 'code', 'bg-green-300': activeTab === 'code'}\"\n @click=\"activeTab = 'code'\">\n Code\n </button>\n <button\n class=\"px-3 py-1 hover:bg-green-300\"\n :class=\"{'bg-green-300': activeTab === 'output'}\"\n @click=\"activeTab = 'output'\">\n Output\n </button>\n <div class=\"ml-auto mr-1 flex\">\n <button\n v-if=\"activeTab === 'output'\"\n class=\"px-2 py-1 mr-1 text-xs bg-gray-500 text-white border-none rounded cursor-pointer hover:bg-gray-600 transition-colors flex items-center\"\n @click=\"copyOutput\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3\" />\n </svg>\n </button>\n <button\n v-if=\"activeTab === 'output'\"\n class=\"px-2 py-1 mr-1 text-xs bg-blue-500 text-white border-none rounded cursor-pointer hover:bg-blue-600 transition-colors flex items-center\"\n @click=\"openDetailModal\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 1v4m0 0h-4m4 0l-5-5\" />\n </svg>\n </button>\n <async-button\n class=\"px-2 py-1 text-xs bg-green-500 text-white border-none rounded cursor-pointer hover:bg-green-600 transition-colors disabled:bg-gray-400\"\n @click=\"executeScript(message, script)\">\n Execute\n </async-button>\n </div>\n </div>\n\n <pre class=\"p-3 whitespace-pre-wrap max-h-[50vh] max-w-[calc(100vw-4rem)] lg:max-w-[calc(100vw-20rem)] overflow-y-auto\" v-show=\"activeTab === 'code'\"><code v-text=\"script\" ref=\"code\" :class=\"'language-' + language\"></code></pre>\n\n <div class=\"p-3 whitespace-pre-wrap max-h-[50vh] overflow-y-auto bg-white border-t max-w-[calc(100vw-4rem)] lg:max-w-[calc(100vw-20rem)] relative\" v-show=\"activeTab === 'output'\">\n <dashboard-chart v-if=\"message.executionResult?.output?.$chart\" :value=\"message.executionResult?.output\" />\n <pre v-else>{{ message.executionResult?.output || 'No output' }}</pre>\n </div>\n\n <modal ref=\"outputModal\" v-if=\"showDetailModal\" containerClass=\"!h-[90vh] !w-[90vw]\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showDetailModal = false;\">×</div>\n <div class=\"h-full overflow-auto\">\n <dashboard-chart v-if=\"message.executionResult?.output?.$chart\" :value=\"message.executionResult?.output\" />\n <pre v-else class=\"whitespace-pre-wrap\">{{ message.executionResult?.output || 'No output' }}</pre>\n </div>\n </template>\n </modal>\n</div>\n";
|
|
3965
|
+
module.exports = "<div class=\"relative border rounded bg-gray-100 text-black text-sm overflow-hidden\">\n <div class=\"flex border-b pt-[1px] text-xs font-medium bg-gray-200\">\n <button\n class=\"px-3 py-1 border-r border-gray-300 hover:bg-green-300\"\n :class=\"{'bg-gray-300': activeTab === 'code', 'bg-green-300': activeTab === 'code'}\"\n @click=\"activeTab = 'code'\">\n Code\n </button>\n <button\n class=\"px-3 py-1 hover:bg-green-300\"\n :class=\"{'bg-green-300': activeTab === 'output'}\"\n @click=\"activeTab = 'output'\">\n Output\n </button>\n <div class=\"ml-auto mr-1 flex\">\n <button\n v-if=\"activeTab === 'output'\"\n class=\"px-2 py-1 mr-1 text-xs bg-gray-500 text-white border-none rounded cursor-pointer hover:bg-gray-600 transition-colors flex items-center\"\n @click=\"copyOutput\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3\" />\n </svg>\n </button>\n <button\n v-if=\"activeTab === 'output'\"\n class=\"px-2 py-1 mr-1 text-xs bg-blue-500 text-white border-none rounded cursor-pointer hover:bg-blue-600 transition-colors flex items-center\"\n @click=\"openDetailModal\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 1v4m0 0h-4m4 0l-5-5\" />\n </svg>\n </button>\n <async-button\n class=\"px-2 py-1 text-xs bg-green-500 text-white border-none rounded cursor-pointer hover:bg-green-600 transition-colors disabled:bg-gray-400\"\n @click=\"executeScript(message, script)\">\n Execute\n </async-button>\n </div>\n </div>\n\n <pre class=\"p-3 whitespace-pre-wrap max-h-[50vh] max-w-[calc(100vw-4rem)] lg:max-w-[calc(100vw-20rem)] overflow-y-auto\" v-show=\"activeTab === 'code'\"><code v-text=\"script\" ref=\"code\" :class=\"'language-' + language\"></code></pre>\n\n <div class=\"p-3 whitespace-pre-wrap max-h-[50vh] overflow-y-auto bg-white border-t max-w-[calc(100vw-4rem)] lg:max-w-[calc(100vw-20rem)] relative\" v-show=\"activeTab === 'output'\">\n <dashboard-chart v-if=\"message.executionResult?.output?.$chart\" :value=\"message.executionResult?.output\" />\n <pre v-else>{{ message.executionResult?.output || 'No output' }}</pre>\n </div>\n\n <modal ref=\"outputModal\" v-if=\"showDetailModal\" containerClass=\"!h-[90vh] !w-[90vw]\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showDetailModal = false;\">×</div>\n <div class=\"h-full overflow-auto\">\n <dashboard-chart v-if=\"message.executionResult?.output?.$chart\" :value=\"message.executionResult?.output\" :responsive=\"true\" />\n <pre v-else class=\"whitespace-pre-wrap\">{{ message.executionResult?.output || 'No output' }}</pre>\n </div>\n </template>\n </modal>\n</div>\n";
|
|
3921
3966
|
|
|
3922
3967
|
/***/ }),
|
|
3923
3968
|
|
|
@@ -4005,7 +4050,7 @@ module.exports = "<div>\n <div class=\"mb-2\">\n <textarea class=\"border bo
|
|
|
4005
4050
|
/***/ ((module) => {
|
|
4006
4051
|
|
|
4007
4052
|
"use strict";
|
|
4008
|
-
module.exports = "<div>\n <div v-if=\"header\" class=\"border-b border-gray-100 px-2 pb-2 text-xl font-bold\">\n {{header}}\n </div>\n <div class=\"text-xl\">\n <canvas ref=\"chart\"></canvas>\n </div>\n</div>\n";
|
|
4053
|
+
module.exports = "<div :class=\"responsive ? 'h-full' : ''\">\n <div v-if=\"header\" class=\"border-b border-gray-100 px-2 pb-2 text-xl font-bold\">\n {{header}}\n </div>\n <div class=\"text-xl\" :class=\"responsive ? 'h-full' : ''\">\n <canvas ref=\"chart\"></canvas>\n </div>\n</div>\n";
|
|
4009
4054
|
|
|
4010
4055
|
/***/ }),
|
|
4011
4056
|
|
|
@@ -4038,7 +4083,7 @@ module.exports = "<div class=\"py-2\">\n <div v-if=\"header\" class=\"border-b
|
|
|
4038
4083
|
/***/ ((module) => {
|
|
4039
4084
|
|
|
4040
4085
|
"use strict";
|
|
4041
|
-
module.exports = "<div>\n <div v-if=\"Array.isArray(result)\">\n <div v-for=\"el in result\">\n <component\n class=\"bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl\"\n :is=\"getComponentForValue(res)\"\n :value=\"res\">\n </component>\n </div>\n </div>\n <div v-else>\n <component\n class=\"bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl\"\n :is=\"getComponentForValue(result)\"\n :value=\"result\">\n </component>\n </div>\n</div>\n";
|
|
4086
|
+
module.exports = "<div>\n <div v-if=\"Array.isArray(result)\">\n <div v-for=\"el in result\">\n <component\n class=\"bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl\"\n :is=\"getComponentForValue(res)\"\n :value=\"res\">\n </component>\n </div>\n </div>\n <div v-else>\n <component\n class=\"bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl\"\n :is=\"getComponentForValue(result)\"\n :value=\"result\">\n </component>\n </div>\n <div class=\"text-right text-sm text-gray-700 mt-1\" v-if=\"finishedEvaluatingAt\">\n Last Evaluated: {{ format.isoToLongDateTime(finishedEvaluatingAt) }}\n </div>\n</div>\n";
|
|
4042
4087
|
|
|
4043
4088
|
/***/ }),
|
|
4044
4089
|
|
|
@@ -4060,7 +4105,7 @@ module.exports = "<div class=\"py-2\">\n <div v-if=\"header\" class=\"border-b
|
|
|
4060
4105
|
/***/ ((module) => {
|
|
4061
4106
|
|
|
4062
4107
|
"use strict";
|
|
4063
|
-
module.exports = "<div class=\"dashboard px-1\">\n <div v-if=\"status === 'loading'\" class=\"max-w-5xl mx-auto text-center\">\n <img src=\"images/loader.gif\" class=\"inline mt-10\">\n </div>\n <div v-if=\"dashboard && status
|
|
4108
|
+
module.exports = "<div class=\"dashboard px-1\">\n <div v-if=\"status === 'loading'\" class=\"max-w-5xl mx-auto text-center\">\n <img src=\"images/loader.gif\" class=\"inline mt-10\">\n </div>\n <div v-if=\"dashboard && status !== 'loading'\" class=\"max-w-5xl mx-auto\">\n <div class=\"flex items-center w-full\" v-if=\"!showEditor\">\n <h2 class=\"mt-4 mb-4 text-gray-900 font-semibold text-xl grow shrink\">{{title}}</h2>\n <div class=\"flex gap-2\">\n <button\n @click=\"showEditor = true\"\n type=\"button\"\n :disabled=\"status === 'evaluating'\"\n class=\"flex items-center 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-ultramarine-600 disabled:cursor-not-allowed disabled:bg-gray-600\">\n <img src=\"images/edit.svg\" class=\"inline h-[1.25em] mr-1\" /> Edit\n </button>\n\n <async-button\n @click=\"evaluateDashboard\"\n type=\"button\"\n :disabled=\"status === 'evaluating'\"\n class=\"flex items-center rounded-md bg-ultramarine-600 px-4 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-ultramarine-600 disabled:cursor-not-allowed disabled:bg-gray-600\"\n >\n <svg class=\"inline h-[1.25em] mr-1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"m670-140 160-100-160-100v200ZM240-600h480v-80H240v80ZM720-40q-83 0-141.5-58.5T520-240q0-83 58.5-141.5T720-440q83 0 141.5 58.5T920-240q0 83-58.5 141.5T720-40ZM120-80v-680q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v267q-19-9-39-15t-41-9v-243H200v562h243q5 31 15.5 59T486-86l-6 6-60-60-60 60-60-60-60 60-60-60-60 60Zm120-200h203q3-21 9-41t15-39H240v80Zm0-160h284q38-37 88.5-58.5T720-520H240v80Zm-40 242v-562 562Z\"/></svg>\n Evaluate\n </async-button>\n </div>\n </div>\n <div v-if=\"!showEditor\" class=\"mt-4 mb-4\">\n <div v-if=\"dashboardResults.length === 0\">\n <div class=\"flex flex-col items-center justify-center py-8\">\n <p class=\"text-gray-700 text-base mb-4\">This dashboard hasn't been evaluated yet.</p>\n <async-button\n @click=\"evaluateDashboard\"\n type=\"button\"\n :disabled=\"status === 'evaluating'\"\n class=\"rounded-md bg-ultramarine-600 px-4 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 disabled:cursor-not-allowed disabled:bg-gray-600\"\n >\n Evaluate Dashboard\n </async-button>\n </div>\n </div>\n <div v-else>\n <dashboard-result :result=\"dashboardResult.result\" :finishedEvaluatingAt=\"dashboardResult.finishedEvaluatingAt\"></dashboard-result>\n </div>\n </div>\n <div v-if=\"showEditor\" class=\"mt-4\">\n <edit-dashboard\n :dashboardId=\"dashboard._id\"\n :code=\"code\"\n :currentDescription=\"description\"\n :currentTitle=\"title\"\n @close=\"showEditor=false;\"\n @update=\"updateCode\"></edit-dashboard>\n </div>\n <div v-if=\"errorMessage\" class=\"rounded-md bg-red-50 p-4 mt-4\">\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\" data-slot=\"icon\">\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16ZM8.28 7.22a.75.75 0 0 0-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 1 0 1.06 1.06L10 11.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L11.06 10l1.72-1.72a.75.75 0 0 0-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\">{{errorMessage}}</h3>\n </div>\n </div>\n </div>\n\n </div>\n <div v-if=\"!dashboard && status !== 'loading'\">\n No dashboard with the given id could be found.\n </div>\n</div>\n";
|
|
4064
4109
|
|
|
4065
4110
|
/***/ }),
|
|
4066
4111
|
|
|
@@ -14574,7 +14619,7 @@ var bson = /*#__PURE__*/Object.freeze({
|
|
|
14574
14619
|
/***/ ((module) => {
|
|
14575
14620
|
|
|
14576
14621
|
"use strict";
|
|
14577
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.0.
|
|
14622
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.0.102","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"},"dependencies":{"archetype":"0.13.1","csv-stringify":"6.3.0","ejson":"^2.2.3","extrovert":"0.0.26","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","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"}}');
|
|
14578
14623
|
|
|
14579
14624
|
/***/ })
|
|
14580
14625
|
|
package/frontend/public/tw.css
CHANGED
|
@@ -866,8 +866,8 @@ video {
|
|
|
866
866
|
height: 2rem;
|
|
867
867
|
}
|
|
868
868
|
|
|
869
|
-
.h-\[
|
|
870
|
-
height:
|
|
869
|
+
.h-\[1\.25em\] {
|
|
870
|
+
height: 1.25em;
|
|
871
871
|
}
|
|
872
872
|
|
|
873
873
|
.h-\[300px\] {
|
|
@@ -1563,6 +1563,11 @@ video {
|
|
|
1563
1563
|
padding-bottom: 1.5rem;
|
|
1564
1564
|
}
|
|
1565
1565
|
|
|
1566
|
+
.py-8 {
|
|
1567
|
+
padding-top: 2rem;
|
|
1568
|
+
padding-bottom: 2rem;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1566
1571
|
.pb-2 {
|
|
1567
1572
|
padding-bottom: 0.5rem;
|
|
1568
1573
|
}
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
<template #body>
|
|
49
49
|
<div class="absolute font-mono right-1 top-1 cursor-pointer text-xl" @click="showDetailModal = false;">×</div>
|
|
50
50
|
<div class="h-full overflow-auto">
|
|
51
|
-
<dashboard-chart v-if="message.executionResult?.output?.$chart" :value="message.executionResult?.output" />
|
|
51
|
+
<dashboard-chart v-if="message.executionResult?.output?.$chart" :value="message.executionResult?.output" :responsive="true" />
|
|
52
52
|
<pre v-else class="whitespace-pre-wrap">{{ message.executionResult?.output || 'No output' }}</pre>
|
|
53
53
|
</div>
|
|
54
54
|
</template>
|
|
@@ -2,20 +2,46 @@
|
|
|
2
2
|
<div v-if="status === 'loading'" class="max-w-5xl mx-auto text-center">
|
|
3
3
|
<img src="images/loader.gif" class="inline mt-10">
|
|
4
4
|
</div>
|
|
5
|
-
<div v-if="dashboard && status
|
|
5
|
+
<div v-if="dashboard && status !== 'loading'" class="max-w-5xl mx-auto">
|
|
6
6
|
<div class="flex items-center w-full" v-if="!showEditor">
|
|
7
7
|
<h2 class="mt-4 mb-4 text-gray-900 font-semibold text-xl grow shrink">{{title}}</h2>
|
|
8
|
-
<div>
|
|
8
|
+
<div class="flex gap-2">
|
|
9
9
|
<button
|
|
10
10
|
@click="showEditor = true"
|
|
11
11
|
type="button"
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
:disabled="status === 'evaluating'"
|
|
13
|
+
class="flex items-center 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-ultramarine-600 disabled:cursor-not-allowed disabled:bg-gray-600">
|
|
14
|
+
<img src="images/edit.svg" class="inline h-[1.25em] mr-1" /> Edit
|
|
14
15
|
</button>
|
|
16
|
+
|
|
17
|
+
<async-button
|
|
18
|
+
@click="evaluateDashboard"
|
|
19
|
+
type="button"
|
|
20
|
+
:disabled="status === 'evaluating'"
|
|
21
|
+
class="flex items-center rounded-md bg-ultramarine-600 px-4 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-ultramarine-600 disabled:cursor-not-allowed disabled:bg-gray-600"
|
|
22
|
+
>
|
|
23
|
+
<svg class="inline h-[1.25em] mr-1" xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="m670-140 160-100-160-100v200ZM240-600h480v-80H240v80ZM720-40q-83 0-141.5-58.5T520-240q0-83 58.5-141.5T720-440q83 0 141.5 58.5T920-240q0 83-58.5 141.5T720-40ZM120-80v-680q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v267q-19-9-39-15t-41-9v-243H200v562h243q5 31 15.5 59T486-86l-6 6-60-60-60 60-60-60-60 60-60-60-60 60Zm120-200h203q3-21 9-41t15-39H240v80Zm0-160h284q38-37 88.5-58.5T720-520H240v80Zm-40 242v-562 562Z"/></svg>
|
|
24
|
+
Evaluate
|
|
25
|
+
</async-button>
|
|
15
26
|
</div>
|
|
16
27
|
</div>
|
|
17
28
|
<div v-if="!showEditor" class="mt-4 mb-4">
|
|
18
|
-
<
|
|
29
|
+
<div v-if="dashboardResults.length === 0">
|
|
30
|
+
<div class="flex flex-col items-center justify-center py-8">
|
|
31
|
+
<p class="text-gray-700 text-base mb-4">This dashboard hasn't been evaluated yet.</p>
|
|
32
|
+
<async-button
|
|
33
|
+
@click="evaluateDashboard"
|
|
34
|
+
type="button"
|
|
35
|
+
:disabled="status === 'evaluating'"
|
|
36
|
+
class="rounded-md bg-ultramarine-600 px-4 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 disabled:cursor-not-allowed disabled:bg-gray-600"
|
|
37
|
+
>
|
|
38
|
+
Evaluate Dashboard
|
|
39
|
+
</async-button>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
<div v-else>
|
|
43
|
+
<dashboard-result :result="dashboardResult.result" :finishedEvaluatingAt="dashboardResult.finishedEvaluatingAt"></dashboard-result>
|
|
44
|
+
</div>
|
|
19
45
|
</div>
|
|
20
46
|
<div v-if="showEditor" class="mt-4">
|
|
21
47
|
<edit-dashboard
|
|
@@ -40,7 +66,7 @@
|
|
|
40
66
|
</div>
|
|
41
67
|
|
|
42
68
|
</div>
|
|
43
|
-
<div v-if="!dashboard && status
|
|
69
|
+
<div v-if="!dashboard && status !== 'loading'">
|
|
44
70
|
No dashboard with the given id could be found.
|
|
45
71
|
</div>
|
|
46
72
|
</div>
|
|
@@ -14,7 +14,7 @@ module.exports = app => app.component('dashboard', {
|
|
|
14
14
|
description: '',
|
|
15
15
|
showEditor: false,
|
|
16
16
|
dashboard: null,
|
|
17
|
-
|
|
17
|
+
dashboardResults: [],
|
|
18
18
|
errorMessage: null
|
|
19
19
|
};
|
|
20
20
|
},
|
|
@@ -31,11 +31,32 @@ module.exports = app => app.component('dashboard', {
|
|
|
31
31
|
} else {
|
|
32
32
|
this.errorMessage = update.error.message;
|
|
33
33
|
}
|
|
34
|
+
},
|
|
35
|
+
async evaluateDashboard() {
|
|
36
|
+
this.status = 'evaluating';
|
|
37
|
+
try {
|
|
38
|
+
const { dashboard, dashboardResult, error } = await api.Dashboard.getDashboard({ dashboardId: this.dashboardId, evaluate: true });
|
|
39
|
+
this.dashboard = dashboard;
|
|
40
|
+
if (error) {
|
|
41
|
+
this.errorMessage = error.message;
|
|
42
|
+
}
|
|
43
|
+
this.code = this.dashboard.code;
|
|
44
|
+
this.title = this.dashboard.title;
|
|
45
|
+
this.description = this.dashboard.description ?? '';
|
|
46
|
+
this.dashboardResults.unshift(dashboardResult);
|
|
47
|
+
} finally {
|
|
48
|
+
this.status = 'loaded';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
computed: {
|
|
53
|
+
dashboardResult() {
|
|
54
|
+
return this.dashboardResults.length > 0 ? this.dashboardResults[0] : null;
|
|
34
55
|
}
|
|
35
56
|
},
|
|
36
57
|
mounted: async function() {
|
|
37
58
|
this.showEditor = this.$route.query.edit;
|
|
38
|
-
const { dashboard,
|
|
59
|
+
const { dashboard, dashboardResults, error } = await api.Dashboard.getDashboard({ dashboardId: this.dashboardId, evaluate: false });
|
|
39
60
|
if (!dashboard) {
|
|
40
61
|
return;
|
|
41
62
|
}
|
|
@@ -46,7 +67,7 @@ module.exports = app => app.component('dashboard', {
|
|
|
46
67
|
this.code = this.dashboard.code;
|
|
47
68
|
this.title = this.dashboard.title;
|
|
48
69
|
this.description = this.dashboard.description ?? '';
|
|
49
|
-
this.
|
|
70
|
+
this.dashboardResults = dashboardResults;
|
|
50
71
|
this.status = 'loaded';
|
|
51
72
|
}
|
|
52
73
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
<div>
|
|
1
|
+
<div :class="responsive ? 'h-full' : ''">
|
|
2
2
|
<div v-if="header" class="border-b border-gray-100 px-2 pb-2 text-xl font-bold">
|
|
3
3
|
{{header}}
|
|
4
4
|
</div>
|
|
5
|
-
<div class="text-xl">
|
|
5
|
+
<div class="text-xl" :class="responsive ? 'h-full' : ''">
|
|
6
6
|
<canvas ref="chart"></canvas>
|
|
7
7
|
</div>
|
|
8
8
|
</div>
|
|
@@ -4,7 +4,7 @@ const template = require('./dashboard-chart.html');
|
|
|
4
4
|
|
|
5
5
|
module.exports = app => app.component('dashboard-chart', {
|
|
6
6
|
template: template,
|
|
7
|
-
props: ['value'],
|
|
7
|
+
props: ['value', 'responsive'],
|
|
8
8
|
mounted() {
|
|
9
9
|
const ctx = this.$refs.chart.getContext('2d');
|
|
10
10
|
const chart = new Chart(ctx, this.value.$chart);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
exports.isoToLongDateTime = function isoToLongDateTime(str) {
|
|
4
|
+
if (!str) {
|
|
5
|
+
return 'Unknown';
|
|
6
|
+
}
|
|
7
|
+
const date = new Date(str);
|
|
8
|
+
return date.toLocaleString('en-US', { month: 'short', day: '2-digit', year: 'numeric', hour: 'numeric', minute: 'numeric' });
|
|
9
|
+
};
|
package/frontend/src/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const { version } = require('../../package.json');
|
|
|
8
8
|
console.log(`Mongoose Studio Version ${version}`);
|
|
9
9
|
|
|
10
10
|
const api = require('./api');
|
|
11
|
+
const format = require('./format');
|
|
11
12
|
const mothership = require('./mothership');
|
|
12
13
|
const { routes } = require('./routes');
|
|
13
14
|
const vanillatoasts = require('vanillatoasts');
|
|
@@ -148,6 +149,7 @@ router.beforeEach((to, from, next) => {
|
|
|
148
149
|
}
|
|
149
150
|
});
|
|
150
151
|
|
|
152
|
+
app.config.globalProperties = { format };
|
|
151
153
|
app.use(router);
|
|
152
154
|
|
|
153
155
|
app.mount('#content');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mongoosejs/studio",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.102",
|
|
4
4
|
"description": "A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.",
|
|
5
5
|
"homepage": "https://studio.mongoosejs.io/",
|
|
6
6
|
"repository": {
|