@mongoosejs/studio 0.2.11 → 0.2.13
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/getEstimatedDocumentCounts.js +38 -0
- package/backend/actions/Model/index.js +1 -0
- package/backend/actions/Model/streamDocumentChanges.js +8 -7
- package/backend/actions/Task/getTasks.js +9 -6
- package/backend/authorize.js +1 -0
- package/backend/index.js +11 -3
- package/eslint.config.js +2 -1
- package/express.js +1 -0
- package/frontend/public/app.js +644 -129
- package/frontend/public/tw.css +181 -12
- package/frontend/src/api.js +6 -0
- package/frontend/src/chat/chat.html +13 -7
- package/frontend/src/document/document.html +26 -0
- package/frontend/src/document/document.js +27 -1
- package/frontend/src/models/models.html +8 -2
- package/frontend/src/models/models.js +34 -0
- package/frontend/src/navbar/navbar.js +1 -1
- package/frontend/src/routes.js +20 -4
- package/frontend/src/task-by-name/task-by-name.html +15 -0
- package/frontend/src/task-by-name/task-by-name.js +78 -0
- package/frontend/src/task-single/task-single.html +157 -0
- package/frontend/src/task-single/task-single.js +116 -0
- package/frontend/src/tasks/task-details/task-details.html +101 -50
- package/frontend/src/tasks/task-details/task-details.js +161 -10
- package/frontend/src/tasks/tasks.html +1 -13
- package/frontend/src/tasks/tasks.js +9 -25
- package/package.json +2 -1
package/frontend/public/app.js
CHANGED
|
@@ -479,6 +479,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
479
479
|
yield { document: doc };
|
|
480
480
|
}
|
|
481
481
|
},
|
|
482
|
+
getEstimatedDocumentCounts: function getEstimatedDocumentCounts() {
|
|
483
|
+
return client.post('', { action: 'Model.getEstimatedDocumentCounts' }).then(res => res.data);
|
|
484
|
+
},
|
|
482
485
|
streamDocumentChanges: async function* streamDocumentChanges(params, options = {}) {
|
|
483
486
|
const pollIntervalMs = 5000;
|
|
484
487
|
while (!options.signal?.aborted) {
|
|
@@ -729,6 +732,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
729
732
|
}
|
|
730
733
|
}
|
|
731
734
|
},
|
|
735
|
+
getEstimatedDocumentCounts: function getEstimatedDocumentCounts() {
|
|
736
|
+
return client.post('/Model/getEstimatedDocumentCounts', {}).then(res => res.data);
|
|
737
|
+
},
|
|
732
738
|
streamDocumentChanges: async function* streamDocumentChanges(params, options = {}) {
|
|
733
739
|
const accessToken = window.localStorage.getItem('_mongooseStudioAccessToken') || null;
|
|
734
740
|
const url = window.MONGOOSE_STUDIO_CONFIG.baseURL + '/Model/streamDocumentChanges?' + new URLSearchParams(params).toString();
|
|
@@ -4502,11 +4508,17 @@ module.exports = app => app.component('document', {
|
|
|
4502
4508
|
}),
|
|
4503
4509
|
async mounted() {
|
|
4504
4510
|
window.pageState = this;
|
|
4511
|
+
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
4512
|
+
window.addEventListener('keydown', this.handleSaveShortcut);
|
|
4513
|
+
}
|
|
4505
4514
|
// Store query parameters from the route (preserved from models page)
|
|
4506
4515
|
this.previousQuery = Object.assign({}, this.$route.query);
|
|
4507
4516
|
await this.refreshDocument({ force: true, source: 'initial' });
|
|
4508
4517
|
},
|
|
4509
|
-
|
|
4518
|
+
beforeUnmount() {
|
|
4519
|
+
if (typeof window !== 'undefined' && window.removeEventListener) {
|
|
4520
|
+
window.removeEventListener('keydown', this.handleSaveShortcut);
|
|
4521
|
+
}
|
|
4510
4522
|
this.stopAutoRefresh();
|
|
4511
4523
|
},
|
|
4512
4524
|
computed: {
|
|
@@ -4536,6 +4548,13 @@ module.exports = app => app.component('document', {
|
|
|
4536
4548
|
canEdit() {
|
|
4537
4549
|
return this.canManipulate && this.viewMode === 'fields';
|
|
4538
4550
|
},
|
|
4551
|
+
keyboardShortcuts() {
|
|
4552
|
+
const shortcuts = [];
|
|
4553
|
+
if (this.editting && this.canManipulate) {
|
|
4554
|
+
shortcuts.push({ command: 'Ctrl + S', description: 'Save document' });
|
|
4555
|
+
}
|
|
4556
|
+
return shortcuts;
|
|
4557
|
+
},
|
|
4539
4558
|
isLambda() {
|
|
4540
4559
|
return !!window?.MONGOOSE_STUDIO_CONFIG?.isLambda;
|
|
4541
4560
|
}
|
|
@@ -4548,6 +4567,19 @@ module.exports = app => app.component('document', {
|
|
|
4548
4567
|
}
|
|
4549
4568
|
},
|
|
4550
4569
|
methods: {
|
|
4570
|
+
handleSaveShortcut(event) {
|
|
4571
|
+
const key = typeof event?.key === 'string' ? event.key.toLowerCase() : '';
|
|
4572
|
+
const isSaveShortcut = (event.ctrlKey || event.metaKey) && key === 's';
|
|
4573
|
+
if (!isSaveShortcut) {
|
|
4574
|
+
return;
|
|
4575
|
+
}
|
|
4576
|
+
if (!this.editting || !this.canManipulate) {
|
|
4577
|
+
return;
|
|
4578
|
+
}
|
|
4579
|
+
|
|
4580
|
+
event.preventDefault();
|
|
4581
|
+
this.shouldShowConfirmModal = true;
|
|
4582
|
+
},
|
|
4551
4583
|
cancelEdit() {
|
|
4552
4584
|
this.changes = {};
|
|
4553
4585
|
this.editting = false;
|
|
@@ -6578,6 +6610,7 @@ module.exports = app => app.component('models', {
|
|
|
6578
6610
|
data: () => ({
|
|
6579
6611
|
models: [],
|
|
6580
6612
|
currentModel: null,
|
|
6613
|
+
modelDocumentCounts: {},
|
|
6581
6614
|
documents: [],
|
|
6582
6615
|
schemaPaths: [],
|
|
6583
6616
|
filteredPaths: [],
|
|
@@ -6642,6 +6675,7 @@ module.exports = app => app.component('models', {
|
|
|
6642
6675
|
document.addEventListener('click', this.onOutsideActionsMenuClick, true);
|
|
6643
6676
|
const { models, readyState } = await api.Model.listModels();
|
|
6644
6677
|
this.models = models;
|
|
6678
|
+
await this.loadModelCounts();
|
|
6645
6679
|
if (this.currentModel == null && this.models.length > 0) {
|
|
6646
6680
|
this.currentModel = this.models[0];
|
|
6647
6681
|
}
|
|
@@ -7147,6 +7181,25 @@ module.exports = app => app.component('models', {
|
|
|
7147
7181
|
|
|
7148
7182
|
return value.toLocaleString();
|
|
7149
7183
|
},
|
|
7184
|
+
formatCompactCount(value) {
|
|
7185
|
+
if (typeof value !== 'number') {
|
|
7186
|
+
return '—';
|
|
7187
|
+
}
|
|
7188
|
+
if (value < 1000) {
|
|
7189
|
+
return `${value}`;
|
|
7190
|
+
}
|
|
7191
|
+
const formatValue = (number, suffix) => {
|
|
7192
|
+
const rounded = (Math.round(number * 10) / 10).toFixed(1).replace(/\.0$/, '');
|
|
7193
|
+
return `${rounded}${suffix}`;
|
|
7194
|
+
};
|
|
7195
|
+
if (value < 1000000) {
|
|
7196
|
+
return formatValue(value / 1000, 'k');
|
|
7197
|
+
}
|
|
7198
|
+
if (value < 1000000000) {
|
|
7199
|
+
return formatValue(value / 1000000, 'M');
|
|
7200
|
+
}
|
|
7201
|
+
return formatValue(value / 1000000000, 'B');
|
|
7202
|
+
},
|
|
7150
7203
|
checkIndexLocation(indexName) {
|
|
7151
7204
|
if (this.schemaIndexes.find(x => x.name == indexName) && this.mongoDBIndexes.find(x => x.name == indexName)) {
|
|
7152
7205
|
return 'text-gray-500';
|
|
@@ -7400,6 +7453,19 @@ module.exports = app => app.component('models', {
|
|
|
7400
7453
|
} else {
|
|
7401
7454
|
this.selectMultiple = true;
|
|
7402
7455
|
}
|
|
7456
|
+
},
|
|
7457
|
+
async loadModelCounts() {
|
|
7458
|
+
if (!Array.isArray(this.models) || this.models.length === 0) {
|
|
7459
|
+
return;
|
|
7460
|
+
}
|
|
7461
|
+
try {
|
|
7462
|
+
const { counts } = await api.Model.getEstimatedDocumentCounts();
|
|
7463
|
+
if (counts && typeof counts === 'object') {
|
|
7464
|
+
this.modelDocumentCounts = counts;
|
|
7465
|
+
}
|
|
7466
|
+
} catch (err) {
|
|
7467
|
+
console.error('Failed to load model document counts', err);
|
|
7468
|
+
}
|
|
7403
7469
|
}
|
|
7404
7470
|
}
|
|
7405
7471
|
});
|
|
@@ -7693,7 +7759,7 @@ module.exports = app => app.component('navbar', {
|
|
|
7693
7759
|
return ['chat index', 'chat'].includes(this.$route.name);
|
|
7694
7760
|
},
|
|
7695
7761
|
taskView() {
|
|
7696
|
-
return ['tasks'].includes(this.$route.name);
|
|
7762
|
+
return ['tasks', 'taskByName', 'taskSingle'].includes(this.$route.name);
|
|
7697
7763
|
},
|
|
7698
7764
|
routeName() {
|
|
7699
7765
|
return this.$route.name;
|
|
@@ -7770,14 +7836,14 @@ module.exports = app => app.component('navbar', {
|
|
|
7770
7836
|
|
|
7771
7837
|
// Role-based access control configuration
|
|
7772
7838
|
const roleAccess = {
|
|
7773
|
-
owner: ['root', 'model', 'document', 'dashboards', 'dashboard', 'team', 'chat'],
|
|
7774
|
-
admin: ['root', 'model', 'document', 'dashboards', 'dashboard', 'team', 'chat'],
|
|
7775
|
-
member: ['root', 'model', 'document', 'dashboards', 'dashboard', 'chat'],
|
|
7839
|
+
owner: ['root', 'model', 'document', 'dashboards', 'dashboard', 'team', 'chat', 'tasks', 'taskByName', 'taskSingle'],
|
|
7840
|
+
admin: ['root', 'model', 'document', 'dashboards', 'dashboard', 'team', 'chat', 'tasks', 'taskByName', 'taskSingle'],
|
|
7841
|
+
member: ['root', 'model', 'document', 'dashboards', 'dashboard', 'chat', 'tasks', 'taskByName', 'taskSingle'],
|
|
7776
7842
|
readonly: ['root', 'model', 'document', 'chat'],
|
|
7777
7843
|
dashboards: ['dashboards', 'dashboard']
|
|
7778
7844
|
};
|
|
7779
7845
|
|
|
7780
|
-
const allowedRoutesForLocalDev = ['document', 'root', 'chat', 'model'];
|
|
7846
|
+
const allowedRoutesForLocalDev = ['document', 'root', 'chat', 'model', 'tasks', 'taskByName', 'taskSingle'];
|
|
7781
7847
|
|
|
7782
7848
|
// Helper function to check if a role has access to a route
|
|
7783
7849
|
function hasAccess(roles, routeName) {
|
|
@@ -7844,6 +7910,22 @@ module.exports = {
|
|
|
7844
7910
|
authorized: true
|
|
7845
7911
|
}
|
|
7846
7912
|
},
|
|
7913
|
+
{
|
|
7914
|
+
path: '/tasks/:name',
|
|
7915
|
+
name: 'taskByName',
|
|
7916
|
+
component: 'task-by-name',
|
|
7917
|
+
meta: {
|
|
7918
|
+
authorized: true
|
|
7919
|
+
}
|
|
7920
|
+
},
|
|
7921
|
+
{
|
|
7922
|
+
path: '/tasks/:name/:id',
|
|
7923
|
+
name: 'taskSingle',
|
|
7924
|
+
component: 'task-single',
|
|
7925
|
+
meta: {
|
|
7926
|
+
authorized: true
|
|
7927
|
+
}
|
|
7928
|
+
},
|
|
7847
7929
|
{
|
|
7848
7930
|
path: '/chat',
|
|
7849
7931
|
name: 'chat index',
|
|
@@ -7903,6 +7985,222 @@ module.exports = app => app.component('splash', {
|
|
|
7903
7985
|
});
|
|
7904
7986
|
|
|
7905
7987
|
|
|
7988
|
+
/***/ },
|
|
7989
|
+
|
|
7990
|
+
/***/ "./frontend/src/task-by-name/task-by-name.js"
|
|
7991
|
+
/*!***************************************************!*\
|
|
7992
|
+
!*** ./frontend/src/task-by-name/task-by-name.js ***!
|
|
7993
|
+
\***************************************************/
|
|
7994
|
+
(module, __unused_webpack_exports, __webpack_require__) {
|
|
7995
|
+
|
|
7996
|
+
"use strict";
|
|
7997
|
+
|
|
7998
|
+
|
|
7999
|
+
// Page: all tasks with a given name. Reuses task-details to render the list (many tasks).
|
|
8000
|
+
const template = __webpack_require__(/*! ./task-by-name.html */ "./frontend/src/task-by-name/task-by-name.html");
|
|
8001
|
+
const api = __webpack_require__(/*! ../api */ "./frontend/src/api.js");
|
|
8002
|
+
|
|
8003
|
+
function buildTaskGroup(name, tasks) {
|
|
8004
|
+
const statusCounts = { pending: 0, succeeded: 0, failed: 0, cancelled: 0, in_progress: 0, unknown: 0 };
|
|
8005
|
+
let lastRun = null;
|
|
8006
|
+
tasks.forEach(task => {
|
|
8007
|
+
const status = task.status || 'unknown';
|
|
8008
|
+
if (Object.prototype.hasOwnProperty.call(statusCounts, status)) {
|
|
8009
|
+
statusCounts[status]++;
|
|
8010
|
+
} else {
|
|
8011
|
+
statusCounts.unknown++;
|
|
8012
|
+
}
|
|
8013
|
+
const taskTime = new Date(task.scheduledAt || task.createdAt || 0);
|
|
8014
|
+
if (!lastRun || taskTime > lastRun) lastRun = taskTime;
|
|
8015
|
+
});
|
|
8016
|
+
return {
|
|
8017
|
+
name,
|
|
8018
|
+
tasks,
|
|
8019
|
+
statusCounts,
|
|
8020
|
+
totalCount: tasks.length,
|
|
8021
|
+
lastRun
|
|
8022
|
+
};
|
|
8023
|
+
}
|
|
8024
|
+
|
|
8025
|
+
module.exports = app => app.component('task-by-name', {
|
|
8026
|
+
template,
|
|
8027
|
+
data: () => ({
|
|
8028
|
+
status: 'init',
|
|
8029
|
+
taskGroup: null,
|
|
8030
|
+
errorMessage: ''
|
|
8031
|
+
}),
|
|
8032
|
+
computed: {
|
|
8033
|
+
taskName() {
|
|
8034
|
+
return this.$route.params.name || '';
|
|
8035
|
+
}
|
|
8036
|
+
},
|
|
8037
|
+
watch: {
|
|
8038
|
+
taskName: {
|
|
8039
|
+
immediate: true,
|
|
8040
|
+
handler() {
|
|
8041
|
+
this.loadTasks();
|
|
8042
|
+
}
|
|
8043
|
+
}
|
|
8044
|
+
},
|
|
8045
|
+
methods: {
|
|
8046
|
+
async loadTasks() {
|
|
8047
|
+
if (!this.taskName) return;
|
|
8048
|
+
this.status = 'init';
|
|
8049
|
+
this.taskGroup = null;
|
|
8050
|
+
this.errorMessage = '';
|
|
8051
|
+
const start = new Date();
|
|
8052
|
+
start.setHours(start.getHours() - 1);
|
|
8053
|
+
const end = new Date();
|
|
8054
|
+
try {
|
|
8055
|
+
const { tasks } = await api.Task.getTasks({
|
|
8056
|
+
name: this.taskName,
|
|
8057
|
+
start,
|
|
8058
|
+
end
|
|
8059
|
+
});
|
|
8060
|
+
this.taskGroup = buildTaskGroup(this.taskName, tasks);
|
|
8061
|
+
this.status = 'loaded';
|
|
8062
|
+
} catch (err) {
|
|
8063
|
+
this.status = 'error';
|
|
8064
|
+
this.errorMessage = err?.response?.data?.message || err.message || 'Failed to load tasks';
|
|
8065
|
+
}
|
|
8066
|
+
},
|
|
8067
|
+
async onTaskCreated() {
|
|
8068
|
+
await this.loadTasks();
|
|
8069
|
+
},
|
|
8070
|
+
async onTaskCancelled() {
|
|
8071
|
+
await this.loadTasks();
|
|
8072
|
+
}
|
|
8073
|
+
}
|
|
8074
|
+
});
|
|
8075
|
+
|
|
8076
|
+
|
|
8077
|
+
/***/ },
|
|
8078
|
+
|
|
8079
|
+
/***/ "./frontend/src/task-single/task-single.js"
|
|
8080
|
+
/*!*************************************************!*\
|
|
8081
|
+
!*** ./frontend/src/task-single/task-single.js ***!
|
|
8082
|
+
\*************************************************/
|
|
8083
|
+
(module, __unused_webpack_exports, __webpack_require__) {
|
|
8084
|
+
|
|
8085
|
+
"use strict";
|
|
8086
|
+
|
|
8087
|
+
|
|
8088
|
+
// Page: one task by id. Dedicated single-task detail UI (not the list).
|
|
8089
|
+
const template = __webpack_require__(/*! ./task-single.html */ "./frontend/src/task-single/task-single.html");
|
|
8090
|
+
const api = __webpack_require__(/*! ../api */ "./frontend/src/api.js");
|
|
8091
|
+
|
|
8092
|
+
module.exports = app => app.component('task-single', {
|
|
8093
|
+
template,
|
|
8094
|
+
data: () => ({
|
|
8095
|
+
status: 'init',
|
|
8096
|
+
task: null,
|
|
8097
|
+
errorMessage: '',
|
|
8098
|
+
showRescheduleModal: false,
|
|
8099
|
+
showRunModal: false,
|
|
8100
|
+
showCancelModal: false,
|
|
8101
|
+
selectedTask: null,
|
|
8102
|
+
newScheduledTime: ''
|
|
8103
|
+
}),
|
|
8104
|
+
computed: {
|
|
8105
|
+
taskId() {
|
|
8106
|
+
return this.$route.params.id || '';
|
|
8107
|
+
},
|
|
8108
|
+
taskByNamePath() {
|
|
8109
|
+
const name = this.task?.name ?? this.$route.params.name ?? '';
|
|
8110
|
+
const path = `/tasks/${encodeURIComponent(name || '')}`;
|
|
8111
|
+
const query = this.$route.query?.status ? { status: this.$route.query.status } : {};
|
|
8112
|
+
return { path, query };
|
|
8113
|
+
},
|
|
8114
|
+
},
|
|
8115
|
+
watch: {
|
|
8116
|
+
'$route.params': {
|
|
8117
|
+
deep: true,
|
|
8118
|
+
handler() {
|
|
8119
|
+
this.loadTask();
|
|
8120
|
+
}
|
|
8121
|
+
}
|
|
8122
|
+
},
|
|
8123
|
+
methods: {
|
|
8124
|
+
getStatusColor(status) {
|
|
8125
|
+
if (status === 'succeeded') return 'bg-green-100 text-green-800';
|
|
8126
|
+
if (status === 'pending') return 'bg-yellow-100 text-yellow-800';
|
|
8127
|
+
if (status === 'cancelled') return 'bg-gray-100 text-gray-800';
|
|
8128
|
+
if (status === 'failed') return 'bg-red-100 text-red-800';
|
|
8129
|
+
if (status === 'in_progress') return 'bg-blue-100 text-blue-800';
|
|
8130
|
+
return 'bg-slate-100 text-slate-800';
|
|
8131
|
+
},
|
|
8132
|
+
formatDate(dateString) {
|
|
8133
|
+
if (!dateString) return 'N/A';
|
|
8134
|
+
return new Date(dateString).toLocaleString();
|
|
8135
|
+
},
|
|
8136
|
+
async loadTask() {
|
|
8137
|
+
if (!this.taskId) return;
|
|
8138
|
+
this.status = 'init';
|
|
8139
|
+
this.task = null;
|
|
8140
|
+
this.errorMessage = '';
|
|
8141
|
+
try {
|
|
8142
|
+
const { doc } = await api.Model.getDocument({ model: 'Task', documentId: this.taskId });
|
|
8143
|
+
this.task = doc;
|
|
8144
|
+
this.status = 'loaded';
|
|
8145
|
+
} catch (err) {
|
|
8146
|
+
const status = err?.response?.status;
|
|
8147
|
+
const notFound = status === 404 || err?.response?.data?.name === 'DocumentNotFoundError';
|
|
8148
|
+
this.status = notFound ? 'notfound' : 'error';
|
|
8149
|
+
this.errorMessage = notFound ? '' : (err?.response?.data?.message || err.message || 'Failed to load task');
|
|
8150
|
+
}
|
|
8151
|
+
},
|
|
8152
|
+
showRescheduleConfirmation(task) {
|
|
8153
|
+
this.selectedTask = task;
|
|
8154
|
+
const defaultTime = new Date();
|
|
8155
|
+
defaultTime.setHours(defaultTime.getHours() + 1);
|
|
8156
|
+
this.newScheduledTime = defaultTime.toISOString().slice(0, 16);
|
|
8157
|
+
this.showRescheduleModal = true;
|
|
8158
|
+
},
|
|
8159
|
+
showRunConfirmation(task) {
|
|
8160
|
+
this.selectedTask = task;
|
|
8161
|
+
this.showRunModal = true;
|
|
8162
|
+
},
|
|
8163
|
+
showCancelConfirmation(task) {
|
|
8164
|
+
this.selectedTask = task;
|
|
8165
|
+
this.showCancelModal = true;
|
|
8166
|
+
},
|
|
8167
|
+
async confirmRescheduleTask() {
|
|
8168
|
+
if (!this.newScheduledTime) return;
|
|
8169
|
+
await api.Task.rescheduleTask({ taskId: this.selectedTask.id, scheduledAt: this.newScheduledTime });
|
|
8170
|
+
this.$toast.success({ title: 'Task Rescheduled', text: `Task ${this.selectedTask.id} has been rescheduled`, });
|
|
8171
|
+
this.showRescheduleModal = false;
|
|
8172
|
+
this.selectedTask = null;
|
|
8173
|
+
this.newScheduledTime = '';
|
|
8174
|
+
await this.loadTask();
|
|
8175
|
+
},
|
|
8176
|
+
async confirmRunTask() {
|
|
8177
|
+
await api.Task.runTask({ taskId: this.selectedTask.id });
|
|
8178
|
+
this.$toast.success({ title: 'Task Started', text: `Task ${this.selectedTask.id} is now running`, type: 'success' });
|
|
8179
|
+
this.showRunModal = false;
|
|
8180
|
+
this.selectedTask = null;
|
|
8181
|
+
await this.loadTask();
|
|
8182
|
+
},
|
|
8183
|
+
goBack() {
|
|
8184
|
+
if (window.history.length > 1) {
|
|
8185
|
+
window.history.back();
|
|
8186
|
+
} else {
|
|
8187
|
+
this.$router.push(this.taskByNamePath);
|
|
8188
|
+
}
|
|
8189
|
+
},
|
|
8190
|
+
async confirmCancelTask() {
|
|
8191
|
+
await api.Task.cancelTask({ taskId: this.selectedTask.id });
|
|
8192
|
+
this.$toast.success({ title: 'Task Cancelled', text: `Task ${this.selectedTask.id} has been cancelled` });
|
|
8193
|
+
this.showCancelModal = false;
|
|
8194
|
+
this.selectedTask = null;
|
|
8195
|
+
this.goBack();
|
|
8196
|
+
}
|
|
8197
|
+
},
|
|
8198
|
+
mounted() {
|
|
8199
|
+
this.loadTask();
|
|
8200
|
+
}
|
|
8201
|
+
});
|
|
8202
|
+
|
|
8203
|
+
|
|
7906
8204
|
/***/ },
|
|
7907
8205
|
|
|
7908
8206
|
/***/ "./frontend/src/tasks/task-details/task-details.js"
|
|
@@ -7917,16 +8215,30 @@ module.exports = app => app.component('splash', {
|
|
|
7917
8215
|
const template = __webpack_require__(/*! ./task-details.html */ "./frontend/src/tasks/task-details/task-details.html");
|
|
7918
8216
|
const api = __webpack_require__(/*! ../../api */ "./frontend/src/api.js");
|
|
7919
8217
|
|
|
8218
|
+
const STATUS_ORDER = ['pending', 'succeeded', 'failed', 'cancelled'];
|
|
8219
|
+
const PIE_COLORS = ['#eab308', '#22c55e', '#ef4444', '#6b7280'];
|
|
8220
|
+
const PIE_HOVER = ['#ca8a04', '#16a34a', '#dc2626', '#4b5563'];
|
|
8221
|
+
|
|
7920
8222
|
module.exports = app => app.component('task-details', {
|
|
7921
|
-
props:
|
|
8223
|
+
props: {
|
|
8224
|
+
taskGroup: { type: Object, required: true },
|
|
8225
|
+
backTo: { type: Object, default: null }
|
|
8226
|
+
},
|
|
7922
8227
|
data: () => ({
|
|
8228
|
+
currentFilter: null,
|
|
7923
8229
|
showRescheduleModal: false,
|
|
7924
8230
|
showRunModal: false,
|
|
7925
8231
|
showCancelModal: false,
|
|
7926
8232
|
selectedTask: null,
|
|
7927
|
-
newScheduledTime: ''
|
|
8233
|
+
newScheduledTime: '',
|
|
8234
|
+
statusView: 'summary',
|
|
8235
|
+
statusChart: null
|
|
7928
8236
|
}),
|
|
7929
8237
|
computed: {
|
|
8238
|
+
backLabel() {
|
|
8239
|
+
if (this.backTo?.path?.startsWith('/tasks/') || this.backTo?.name === 'taskByName') return `Back to ${this.taskGroup?.name || 'tasks'}`;
|
|
8240
|
+
return 'Back to Task Groups';
|
|
8241
|
+
},
|
|
7930
8242
|
sortedTasks() {
|
|
7931
8243
|
let tasks = this.taskGroup.tasks;
|
|
7932
8244
|
|
|
@@ -7940,9 +8252,123 @@ module.exports = app => app.component('task-details', {
|
|
|
7940
8252
|
const dateB = new Date(b.scheduledAt || b.createdAt || 0);
|
|
7941
8253
|
return dateB - dateA; // Most recent first
|
|
7942
8254
|
});
|
|
8255
|
+
},
|
|
8256
|
+
pieChartData() {
|
|
8257
|
+
const counts = this.taskGroup?.statusCounts || {};
|
|
8258
|
+
return {
|
|
8259
|
+
labels: ['Pending', 'Succeeded', 'Failed', 'Cancelled'],
|
|
8260
|
+
datasets: [{
|
|
8261
|
+
data: STATUS_ORDER.map(s => counts[s] || 0),
|
|
8262
|
+
backgroundColor: PIE_COLORS,
|
|
8263
|
+
hoverBackgroundColor: PIE_HOVER,
|
|
8264
|
+
borderWidth: 2,
|
|
8265
|
+
borderColor: '#fff'
|
|
8266
|
+
}]
|
|
8267
|
+
};
|
|
8268
|
+
},
|
|
8269
|
+
statusOrderForDisplay() {
|
|
8270
|
+
return STATUS_ORDER;
|
|
7943
8271
|
}
|
|
7944
8272
|
},
|
|
8273
|
+
watch: {
|
|
8274
|
+
'$route.query.status': {
|
|
8275
|
+
handler(status) {
|
|
8276
|
+
this.currentFilter = status || null;
|
|
8277
|
+
},
|
|
8278
|
+
immediate: true
|
|
8279
|
+
},
|
|
8280
|
+
statusView(val) {
|
|
8281
|
+
if (val !== 'chart') this.destroyStatusChart();
|
|
8282
|
+
else {
|
|
8283
|
+
this.$nextTick(() => {
|
|
8284
|
+
requestAnimationFrame(() => this.ensureStatusChart());
|
|
8285
|
+
});
|
|
8286
|
+
}
|
|
8287
|
+
},
|
|
8288
|
+
taskGroup: {
|
|
8289
|
+
deep: true,
|
|
8290
|
+
handler() {
|
|
8291
|
+
this.$nextTick(() => {
|
|
8292
|
+
requestAnimationFrame(() => this.ensureStatusChart());
|
|
8293
|
+
});
|
|
8294
|
+
}
|
|
8295
|
+
},
|
|
8296
|
+
},
|
|
7945
8297
|
methods: {
|
|
8298
|
+
destroyStatusChart() {
|
|
8299
|
+
if (this.statusChart) {
|
|
8300
|
+
try {
|
|
8301
|
+
this.statusChart.destroy();
|
|
8302
|
+
} catch (_) {
|
|
8303
|
+
// ignore Chart.js teardown errors
|
|
8304
|
+
}
|
|
8305
|
+
this.statusChart = null;
|
|
8306
|
+
}
|
|
8307
|
+
},
|
|
8308
|
+
isChartCanvasReady(canvas) {
|
|
8309
|
+
return canvas && typeof canvas.getContext === 'function' && canvas.isConnected && canvas.offsetParent != null;
|
|
8310
|
+
},
|
|
8311
|
+
ensureStatusChart() {
|
|
8312
|
+
if (this.statusView !== 'chart' || !this.taskGroup || this.taskGroup.totalCount === 0) {
|
|
8313
|
+
this.destroyStatusChart();
|
|
8314
|
+
return;
|
|
8315
|
+
}
|
|
8316
|
+
const canvas = this.$refs.statusPieChart;
|
|
8317
|
+
if (!canvas || !this.isChartCanvasReady(canvas)) return;
|
|
8318
|
+
const Chart = typeof window !== 'undefined' && window.Chart;
|
|
8319
|
+
if (!Chart) return;
|
|
8320
|
+
const data = this.pieChartData;
|
|
8321
|
+
if (this.statusChart) {
|
|
8322
|
+
try {
|
|
8323
|
+
this.statusChart.data.labels = data.labels;
|
|
8324
|
+
this.statusChart.data.datasets[0].data = data.datasets[0].data;
|
|
8325
|
+
this.statusChart.update('none');
|
|
8326
|
+
} catch (_) {
|
|
8327
|
+
this.destroyStatusChart();
|
|
8328
|
+
}
|
|
8329
|
+
return;
|
|
8330
|
+
}
|
|
8331
|
+
try {
|
|
8332
|
+
this.statusChart = new Chart(canvas, {
|
|
8333
|
+
type: 'doughnut',
|
|
8334
|
+
data,
|
|
8335
|
+
options: {
|
|
8336
|
+
responsive: false,
|
|
8337
|
+
maintainAspectRatio: false,
|
|
8338
|
+
animation: false,
|
|
8339
|
+
layout: {
|
|
8340
|
+
padding: 8
|
|
8341
|
+
},
|
|
8342
|
+
onClick: (_evt, elements) => {
|
|
8343
|
+
if (elements && elements.length > 0) {
|
|
8344
|
+
const status = STATUS_ORDER[elements[0].index];
|
|
8345
|
+
this.$nextTick(() => this.filterByStatus(status));
|
|
8346
|
+
}
|
|
8347
|
+
},
|
|
8348
|
+
plugins: {
|
|
8349
|
+
legend: {
|
|
8350
|
+
display: true,
|
|
8351
|
+
position: 'bottom'
|
|
8352
|
+
}
|
|
8353
|
+
}
|
|
8354
|
+
}
|
|
8355
|
+
});
|
|
8356
|
+
} catch (_) {
|
|
8357
|
+
this.statusChart = null;
|
|
8358
|
+
}
|
|
8359
|
+
},
|
|
8360
|
+
statusLabel(status) {
|
|
8361
|
+
return status.charAt(0).toUpperCase() + status.slice(1).replace('_', ' ');
|
|
8362
|
+
},
|
|
8363
|
+
getStatusPillClass(status) {
|
|
8364
|
+
const classes = {
|
|
8365
|
+
pending: 'bg-yellow-200 text-yellow-900 ring-2 ring-yellow-500',
|
|
8366
|
+
succeeded: 'bg-green-200 text-green-900 ring-2 ring-green-500',
|
|
8367
|
+
failed: 'bg-red-200 text-red-900 ring-2 ring-red-500',
|
|
8368
|
+
cancelled: 'bg-gray-200 text-gray-900 ring-2 ring-gray-500'
|
|
8369
|
+
};
|
|
8370
|
+
return classes[status] || 'bg-slate-200 text-slate-900 ring-2 ring-slate-500';
|
|
8371
|
+
},
|
|
7946
8372
|
getStatusColor(status) {
|
|
7947
8373
|
if (status === 'succeeded') {
|
|
7948
8374
|
return 'bg-green-100 text-green-800';
|
|
@@ -7979,15 +8405,35 @@ module.exports = app => app.component('task-details', {
|
|
|
7979
8405
|
this.$emit('task-cancelled');
|
|
7980
8406
|
},
|
|
7981
8407
|
filterByStatus(status) {
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
8408
|
+
const next = this.currentFilter === status ? null : status;
|
|
8409
|
+
this.currentFilter = next;
|
|
8410
|
+
const query = { ...this.$route.query };
|
|
8411
|
+
if (next) query.status = next;
|
|
8412
|
+
else delete query.status;
|
|
8413
|
+
this.$router.replace({ path: this.$route.path, query });
|
|
8414
|
+
},
|
|
8415
|
+
clearFilter() {
|
|
8416
|
+
this.currentFilter = null;
|
|
8417
|
+
const query = { ...this.$route.query };
|
|
8418
|
+
delete query.status;
|
|
8419
|
+
this.$router.replace({ path: this.$route.path, query });
|
|
8420
|
+
},
|
|
8421
|
+
goBack() {
|
|
8422
|
+
if (this.backTo) {
|
|
8423
|
+
if (window.history.length > 1) {
|
|
8424
|
+
window.history.back();
|
|
8425
|
+
} else {
|
|
8426
|
+
this.$router.push(this.backTo);
|
|
8427
|
+
}
|
|
7985
8428
|
} else {
|
|
7986
|
-
this.$emit('
|
|
8429
|
+
this.$emit('back');
|
|
7987
8430
|
}
|
|
7988
8431
|
},
|
|
7989
|
-
|
|
7990
|
-
|
|
8432
|
+
taskDetailRoute(task) {
|
|
8433
|
+
const id = String(task.id || task._id);
|
|
8434
|
+
const path = `/tasks/${encodeURIComponent(this.taskGroup.name || '')}/${id}`;
|
|
8435
|
+
const query = this.currentFilter ? { status: this.currentFilter } : {};
|
|
8436
|
+
return { path, query };
|
|
7991
8437
|
},
|
|
7992
8438
|
showRescheduleConfirmation(task) {
|
|
7993
8439
|
this.selectedTask = task;
|
|
@@ -8087,11 +8533,14 @@ module.exports = app => app.component('task-details', {
|
|
|
8087
8533
|
|
|
8088
8534
|
},
|
|
8089
8535
|
mounted() {
|
|
8090
|
-
// Check if the task group was already filtered when passed from parent
|
|
8091
8536
|
if (this.taskGroup.filteredStatus && !this.currentFilter) {
|
|
8092
|
-
this
|
|
8537
|
+
this.currentFilter = this.taskGroup.filteredStatus;
|
|
8538
|
+
this.$router.replace({ path: this.$route.path, query: { ...this.$route.query, status: this.taskGroup.filteredStatus } });
|
|
8093
8539
|
}
|
|
8094
8540
|
},
|
|
8541
|
+
beforeUnmount() {
|
|
8542
|
+
this.destroyStatusChart();
|
|
8543
|
+
},
|
|
8095
8544
|
template: template
|
|
8096
8545
|
});
|
|
8097
8546
|
|
|
@@ -8115,11 +8564,12 @@ module.exports = app => app.component('tasks', {
|
|
|
8115
8564
|
status: 'init',
|
|
8116
8565
|
tasks: [],
|
|
8117
8566
|
groupedTasks: {},
|
|
8118
|
-
selectedRange: '
|
|
8567
|
+
selectedRange: 'last_hour',
|
|
8119
8568
|
start: null,
|
|
8120
8569
|
end: null,
|
|
8121
8570
|
dateFilters: [
|
|
8122
8571
|
{ value: 'all', label: 'All Time' },
|
|
8572
|
+
{ value: 'last_hour', label: 'Last Hour' },
|
|
8123
8573
|
{ value: 'today', label: 'Today' },
|
|
8124
8574
|
{ value: 'yesterday', label: 'Yesterday' },
|
|
8125
8575
|
{ value: 'thisWeek', label: 'This Week' },
|
|
@@ -8138,10 +8588,6 @@ module.exports = app => app.component('tasks', {
|
|
|
8138
8588
|
],
|
|
8139
8589
|
searchQuery: '',
|
|
8140
8590
|
searchTimeout: null,
|
|
8141
|
-
// Task details view state
|
|
8142
|
-
showTaskDetails: false,
|
|
8143
|
-
selectedTaskGroup: null,
|
|
8144
|
-
taskDetailsFilter: null,
|
|
8145
8591
|
// Create task modal state
|
|
8146
8592
|
showCreateTaskModal: false,
|
|
8147
8593
|
newTask: {
|
|
@@ -8177,28 +8623,10 @@ module.exports = app => app.component('tasks', {
|
|
|
8177
8623
|
this.groupedTasks = groupedTasks;
|
|
8178
8624
|
},
|
|
8179
8625
|
openTaskGroupDetails(group) {
|
|
8180
|
-
this.
|
|
8181
|
-
this.showTaskDetails = true;
|
|
8626
|
+
this.$router.push({ path: `/tasks/${encodeURIComponent(group.name || '')}` });
|
|
8182
8627
|
},
|
|
8183
8628
|
openTaskGroupDetailsWithFilter(group, status) {
|
|
8184
|
-
|
|
8185
|
-
const filteredGroup = {
|
|
8186
|
-
...group,
|
|
8187
|
-
tasks: group.tasks.filter(task => task.status === status),
|
|
8188
|
-
filteredStatus: status
|
|
8189
|
-
};
|
|
8190
|
-
this.selectedTaskGroup = filteredGroup;
|
|
8191
|
-
this.taskDetailsFilter = status;
|
|
8192
|
-
this.showTaskDetails = true;
|
|
8193
|
-
},
|
|
8194
|
-
async onTaskCancelled() {
|
|
8195
|
-
// Refresh the task data when a task is cancelled
|
|
8196
|
-
await this.getTasks();
|
|
8197
|
-
},
|
|
8198
|
-
hideTaskDetails() {
|
|
8199
|
-
this.showTaskDetails = false;
|
|
8200
|
-
this.selectedTaskGroup = null;
|
|
8201
|
-
this.taskDetailsFilter = null;
|
|
8629
|
+
this.$router.push({ path: `/tasks/${encodeURIComponent(group.name || '')}`, query: status ? { status } : {} });
|
|
8202
8630
|
},
|
|
8203
8631
|
async onTaskCreated() {
|
|
8204
8632
|
// Refresh the task data when a new task is created
|
|
@@ -8362,6 +8790,11 @@ module.exports = app => app.component('tasks', {
|
|
|
8362
8790
|
let start, end;
|
|
8363
8791
|
|
|
8364
8792
|
switch (this.selectedRange) {
|
|
8793
|
+
case 'last_hour':
|
|
8794
|
+
start = new Date();
|
|
8795
|
+
start.setHours(start.getHours() - 1);
|
|
8796
|
+
end = new Date();
|
|
8797
|
+
break;
|
|
8365
8798
|
case 'today':
|
|
8366
8799
|
start = new Date();
|
|
8367
8800
|
start.setHours(0, 0, 0, 0);
|
|
@@ -8880,6 +9313,12 @@ var map = {
|
|
|
8880
9313
|
"./splash/splash": "./frontend/src/splash/splash.js",
|
|
8881
9314
|
"./splash/splash.html": "./frontend/src/splash/splash.html",
|
|
8882
9315
|
"./splash/splash.js": "./frontend/src/splash/splash.js",
|
|
9316
|
+
"./task-by-name/task-by-name": "./frontend/src/task-by-name/task-by-name.js",
|
|
9317
|
+
"./task-by-name/task-by-name.html": "./frontend/src/task-by-name/task-by-name.html",
|
|
9318
|
+
"./task-by-name/task-by-name.js": "./frontend/src/task-by-name/task-by-name.js",
|
|
9319
|
+
"./task-single/task-single": "./frontend/src/task-single/task-single.js",
|
|
9320
|
+
"./task-single/task-single.html": "./frontend/src/task-single/task-single.html",
|
|
9321
|
+
"./task-single/task-single.js": "./frontend/src/task-single/task-single.js",
|
|
8883
9322
|
"./tasks/task-details/task-details": "./frontend/src/tasks/task-details/task-details.js",
|
|
8884
9323
|
"./tasks/task-details/task-details.html": "./frontend/src/tasks/task-details/task-details.html",
|
|
8885
9324
|
"./tasks/task-details/task-details.js": "./frontend/src/tasks/task-details/task-details.js",
|
|
@@ -8983,7 +9422,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
8983
9422
|
/* harmony export */ });
|
|
8984
9423
|
/* harmony import */ var _vue_shared__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @vue/shared */ "./node_modules/@vue/shared/dist/shared.esm-bundler.js");
|
|
8985
9424
|
/**
|
|
8986
|
-
* @vue/reactivity v3.5.
|
|
9425
|
+
* @vue/reactivity v3.5.29
|
|
8987
9426
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
8988
9427
|
* @license MIT
|
|
8989
9428
|
**/
|
|
@@ -8995,6 +9434,7 @@ function warn(msg, ...args) {
|
|
|
8995
9434
|
|
|
8996
9435
|
let activeEffectScope;
|
|
8997
9436
|
class EffectScope {
|
|
9437
|
+
// TODO isolatedDeclarations "__v_skip"
|
|
8998
9438
|
constructor(detached = false) {
|
|
8999
9439
|
this.detached = detached;
|
|
9000
9440
|
/**
|
|
@@ -9014,6 +9454,7 @@ class EffectScope {
|
|
|
9014
9454
|
*/
|
|
9015
9455
|
this.cleanups = [];
|
|
9016
9456
|
this._isPaused = false;
|
|
9457
|
+
this.__v_skip = true;
|
|
9017
9458
|
this.parent = activeEffectScope;
|
|
9018
9459
|
if (!detached && activeEffectScope) {
|
|
9019
9460
|
this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(
|
|
@@ -11121,7 +11562,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
11121
11562
|
/* harmony import */ var _vue_reactivity__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @vue/reactivity */ "./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js");
|
|
11122
11563
|
/* harmony import */ var _vue_shared__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @vue/shared */ "./node_modules/@vue/shared/dist/shared.esm-bundler.js");
|
|
11123
11564
|
/**
|
|
11124
|
-
* @vue/runtime-core v3.5.
|
|
11565
|
+
* @vue/runtime-core v3.5.29
|
|
11125
11566
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
11126
11567
|
* @license MIT
|
|
11127
11568
|
**/
|
|
@@ -12326,7 +12767,22 @@ function moveTeleport(vnode, container, parentAnchor, { o: { insert }, m: move }
|
|
|
12326
12767
|
function hydrateTeleport(node, vnode, parentComponent, parentSuspense, slotScopeIds, optimized, {
|
|
12327
12768
|
o: { nextSibling, parentNode, querySelector, insert, createText }
|
|
12328
12769
|
}, hydrateChildren) {
|
|
12329
|
-
function
|
|
12770
|
+
function hydrateAnchor(target2, targetNode) {
|
|
12771
|
+
let targetAnchor = targetNode;
|
|
12772
|
+
while (targetAnchor) {
|
|
12773
|
+
if (targetAnchor && targetAnchor.nodeType === 8) {
|
|
12774
|
+
if (targetAnchor.data === "teleport start anchor") {
|
|
12775
|
+
vnode.targetStart = targetAnchor;
|
|
12776
|
+
} else if (targetAnchor.data === "teleport anchor") {
|
|
12777
|
+
vnode.targetAnchor = targetAnchor;
|
|
12778
|
+
target2._lpa = vnode.targetAnchor && nextSibling(vnode.targetAnchor);
|
|
12779
|
+
break;
|
|
12780
|
+
}
|
|
12781
|
+
}
|
|
12782
|
+
targetAnchor = nextSibling(targetAnchor);
|
|
12783
|
+
}
|
|
12784
|
+
}
|
|
12785
|
+
function hydrateDisabledTeleport(node2, vnode2) {
|
|
12330
12786
|
vnode2.anchor = hydrateChildren(
|
|
12331
12787
|
nextSibling(node2),
|
|
12332
12788
|
vnode2,
|
|
@@ -12336,8 +12792,6 @@ function hydrateTeleport(node, vnode, parentComponent, parentSuspense, slotScope
|
|
|
12336
12792
|
slotScopeIds,
|
|
12337
12793
|
optimized
|
|
12338
12794
|
);
|
|
12339
|
-
vnode2.targetStart = targetStart;
|
|
12340
|
-
vnode2.targetAnchor = targetAnchor;
|
|
12341
12795
|
}
|
|
12342
12796
|
const target = vnode.target = resolveTarget(
|
|
12343
12797
|
vnode.props,
|
|
@@ -12348,27 +12802,22 @@ function hydrateTeleport(node, vnode, parentComponent, parentSuspense, slotScope
|
|
|
12348
12802
|
const targetNode = target._lpa || target.firstChild;
|
|
12349
12803
|
if (vnode.shapeFlag & 16) {
|
|
12350
12804
|
if (disabled) {
|
|
12351
|
-
hydrateDisabledTeleport(
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12805
|
+
hydrateDisabledTeleport(node, vnode);
|
|
12806
|
+
hydrateAnchor(target, targetNode);
|
|
12807
|
+
if (!vnode.targetAnchor) {
|
|
12808
|
+
prepareAnchor(
|
|
12809
|
+
target,
|
|
12810
|
+
vnode,
|
|
12811
|
+
createText,
|
|
12812
|
+
insert,
|
|
12813
|
+
// if target is the same as the main view, insert anchors before current node
|
|
12814
|
+
// to avoid hydrating mismatch
|
|
12815
|
+
parentNode(node) === target ? node : null
|
|
12816
|
+
);
|
|
12817
|
+
}
|
|
12357
12818
|
} else {
|
|
12358
12819
|
vnode.anchor = nextSibling(node);
|
|
12359
|
-
|
|
12360
|
-
while (targetAnchor) {
|
|
12361
|
-
if (targetAnchor && targetAnchor.nodeType === 8) {
|
|
12362
|
-
if (targetAnchor.data === "teleport start anchor") {
|
|
12363
|
-
vnode.targetStart = targetAnchor;
|
|
12364
|
-
} else if (targetAnchor.data === "teleport anchor") {
|
|
12365
|
-
vnode.targetAnchor = targetAnchor;
|
|
12366
|
-
target._lpa = vnode.targetAnchor && nextSibling(vnode.targetAnchor);
|
|
12367
|
-
break;
|
|
12368
|
-
}
|
|
12369
|
-
}
|
|
12370
|
-
targetAnchor = nextSibling(targetAnchor);
|
|
12371
|
-
}
|
|
12820
|
+
hydrateAnchor(target, targetNode);
|
|
12372
12821
|
if (!vnode.targetAnchor) {
|
|
12373
12822
|
prepareAnchor(target, vnode, createText, insert);
|
|
12374
12823
|
}
|
|
@@ -12386,7 +12835,9 @@ function hydrateTeleport(node, vnode, parentComponent, parentSuspense, slotScope
|
|
|
12386
12835
|
updateCssVars(vnode, disabled);
|
|
12387
12836
|
} else if (disabled) {
|
|
12388
12837
|
if (vnode.shapeFlag & 16) {
|
|
12389
|
-
hydrateDisabledTeleport(node, vnode
|
|
12838
|
+
hydrateDisabledTeleport(node, vnode);
|
|
12839
|
+
vnode.targetStart = node;
|
|
12840
|
+
vnode.targetAnchor = nextSibling(node);
|
|
12390
12841
|
}
|
|
12391
12842
|
}
|
|
12392
12843
|
return vnode.anchor && nextSibling(vnode.anchor);
|
|
@@ -12410,13 +12861,13 @@ function updateCssVars(vnode, isDisabled) {
|
|
|
12410
12861
|
ctx.ut();
|
|
12411
12862
|
}
|
|
12412
12863
|
}
|
|
12413
|
-
function prepareAnchor(target, vnode, createText, insert) {
|
|
12864
|
+
function prepareAnchor(target, vnode, createText, insert, anchor = null) {
|
|
12414
12865
|
const targetStart = vnode.targetStart = createText("");
|
|
12415
12866
|
const targetAnchor = vnode.targetAnchor = createText("");
|
|
12416
12867
|
targetStart[TeleportEndKey] = targetAnchor;
|
|
12417
12868
|
if (target) {
|
|
12418
|
-
insert(targetStart, target);
|
|
12419
|
-
insert(targetAnchor, target);
|
|
12869
|
+
insert(targetStart, target, anchor);
|
|
12870
|
+
insert(targetAnchor, target, anchor);
|
|
12420
12871
|
}
|
|
12421
12872
|
return targetAnchor;
|
|
12422
12873
|
}
|
|
@@ -12640,6 +13091,7 @@ function resolveTransitionHooks(vnode, props, state, instance, postClone) {
|
|
|
12640
13091
|
callHook(hook, [el]);
|
|
12641
13092
|
},
|
|
12642
13093
|
enter(el) {
|
|
13094
|
+
if (leavingVNodesCache[key] === vnode) return;
|
|
12643
13095
|
let hook = onEnter;
|
|
12644
13096
|
let afterHook = onAfterEnter;
|
|
12645
13097
|
let cancelHook = onEnterCancelled;
|
|
@@ -12653,7 +13105,7 @@ function resolveTransitionHooks(vnode, props, state, instance, postClone) {
|
|
|
12653
13105
|
}
|
|
12654
13106
|
}
|
|
12655
13107
|
let called = false;
|
|
12656
|
-
|
|
13108
|
+
el[enterCbKey] = (cancelled) => {
|
|
12657
13109
|
if (called) return;
|
|
12658
13110
|
called = true;
|
|
12659
13111
|
if (cancelled) {
|
|
@@ -12666,6 +13118,7 @@ function resolveTransitionHooks(vnode, props, state, instance, postClone) {
|
|
|
12666
13118
|
}
|
|
12667
13119
|
el[enterCbKey] = void 0;
|
|
12668
13120
|
};
|
|
13121
|
+
const done = el[enterCbKey].bind(null, false);
|
|
12669
13122
|
if (hook) {
|
|
12670
13123
|
callAsyncHook(hook, [el, done]);
|
|
12671
13124
|
} else {
|
|
@@ -12685,7 +13138,7 @@ function resolveTransitionHooks(vnode, props, state, instance, postClone) {
|
|
|
12685
13138
|
}
|
|
12686
13139
|
callHook(onBeforeLeave, [el]);
|
|
12687
13140
|
let called = false;
|
|
12688
|
-
|
|
13141
|
+
el[leaveCbKey] = (cancelled) => {
|
|
12689
13142
|
if (called) return;
|
|
12690
13143
|
called = true;
|
|
12691
13144
|
remove();
|
|
@@ -12699,6 +13152,7 @@ function resolveTransitionHooks(vnode, props, state, instance, postClone) {
|
|
|
12699
13152
|
delete leavingVNodesCache[key2];
|
|
12700
13153
|
}
|
|
12701
13154
|
};
|
|
13155
|
+
const done = el[leaveCbKey].bind(null, false);
|
|
12702
13156
|
leavingVNodesCache[key2] = vnode;
|
|
12703
13157
|
if (onLeave) {
|
|
12704
13158
|
callAsyncHook(onLeave, [el, done]);
|
|
@@ -12811,8 +13265,7 @@ function useTemplateRef(key) {
|
|
|
12811
13265
|
const r = (0,_vue_reactivity__WEBPACK_IMPORTED_MODULE_0__.shallowRef)(null);
|
|
12812
13266
|
if (i) {
|
|
12813
13267
|
const refs = i.refs === _vue_shared__WEBPACK_IMPORTED_MODULE_1__.EMPTY_OBJ ? i.refs = {} : i.refs;
|
|
12814
|
-
|
|
12815
|
-
if ( true && (desc = Object.getOwnPropertyDescriptor(refs, key)) && !desc.configurable) {
|
|
13268
|
+
if ( true && isTemplateRefKey(refs, key)) {
|
|
12816
13269
|
warn$1(`useTemplateRef('${key}') already exists.`);
|
|
12817
13270
|
} else {
|
|
12818
13271
|
Object.defineProperty(refs, key, {
|
|
@@ -12832,6 +13285,10 @@ function useTemplateRef(key) {
|
|
|
12832
13285
|
}
|
|
12833
13286
|
return ret;
|
|
12834
13287
|
}
|
|
13288
|
+
function isTemplateRefKey(refs, key) {
|
|
13289
|
+
let desc;
|
|
13290
|
+
return !!((desc = Object.getOwnPropertyDescriptor(refs, key)) && !desc.configurable);
|
|
13291
|
+
}
|
|
12835
13292
|
|
|
12836
13293
|
const pendingSetRefMap = /* @__PURE__ */ new WeakMap();
|
|
12837
13294
|
function setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) {
|
|
@@ -12877,10 +13334,19 @@ function setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) {
|
|
|
12877
13334
|
return false;
|
|
12878
13335
|
}
|
|
12879
13336
|
}
|
|
13337
|
+
if (isTemplateRefKey(refs, key)) {
|
|
13338
|
+
return false;
|
|
13339
|
+
}
|
|
12880
13340
|
return (0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.hasOwn)(rawSetupState, key);
|
|
12881
13341
|
};
|
|
12882
|
-
const canSetRef = (ref2) => {
|
|
12883
|
-
|
|
13342
|
+
const canSetRef = (ref2, key) => {
|
|
13343
|
+
if ( true && knownTemplateRefs.has(ref2)) {
|
|
13344
|
+
return false;
|
|
13345
|
+
}
|
|
13346
|
+
if (key && isTemplateRefKey(refs, key)) {
|
|
13347
|
+
return false;
|
|
13348
|
+
}
|
|
13349
|
+
return true;
|
|
12884
13350
|
};
|
|
12885
13351
|
if (oldRef != null && oldRef !== ref) {
|
|
12886
13352
|
invalidatePendingSetRef(oldRawRef);
|
|
@@ -12890,10 +13356,10 @@ function setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) {
|
|
|
12890
13356
|
setupState[oldRef] = null;
|
|
12891
13357
|
}
|
|
12892
13358
|
} else if ((0,_vue_reactivity__WEBPACK_IMPORTED_MODULE_0__.isRef)(oldRef)) {
|
|
12893
|
-
|
|
13359
|
+
const oldRawRefAtom = oldRawRef;
|
|
13360
|
+
if (canSetRef(oldRef, oldRawRefAtom.k)) {
|
|
12894
13361
|
oldRef.value = null;
|
|
12895
13362
|
}
|
|
12896
|
-
const oldRawRefAtom = oldRawRef;
|
|
12897
13363
|
if (oldRawRefAtom.k) refs[oldRawRefAtom.k] = null;
|
|
12898
13364
|
}
|
|
12899
13365
|
}
|
|
@@ -12917,7 +13383,7 @@ function setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) {
|
|
|
12917
13383
|
}
|
|
12918
13384
|
} else {
|
|
12919
13385
|
const newVal = [refValue];
|
|
12920
|
-
if (canSetRef(ref)) {
|
|
13386
|
+
if (canSetRef(ref, rawRef.k)) {
|
|
12921
13387
|
ref.value = newVal;
|
|
12922
13388
|
}
|
|
12923
13389
|
if (rawRef.k) refs[rawRef.k] = newVal;
|
|
@@ -12932,7 +13398,7 @@ function setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) {
|
|
|
12932
13398
|
setupState[ref] = value;
|
|
12933
13399
|
}
|
|
12934
13400
|
} else if (_isRef) {
|
|
12935
|
-
if (canSetRef(ref)) {
|
|
13401
|
+
if (canSetRef(ref, rawRef.k)) {
|
|
12936
13402
|
ref.value = value;
|
|
12937
13403
|
}
|
|
12938
13404
|
if (rawRef.k) refs[rawRef.k] = value;
|
|
@@ -14726,13 +15192,24 @@ function withAsyncContext(getAwaitable) {
|
|
|
14726
15192
|
}
|
|
14727
15193
|
let awaitable = getAwaitable();
|
|
14728
15194
|
unsetCurrentInstance();
|
|
15195
|
+
const cleanup = () => {
|
|
15196
|
+
if (getCurrentInstance() !== ctx) ctx.scope.off();
|
|
15197
|
+
unsetCurrentInstance();
|
|
15198
|
+
};
|
|
14729
15199
|
if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.isPromise)(awaitable)) {
|
|
14730
15200
|
awaitable = awaitable.catch((e) => {
|
|
14731
15201
|
setCurrentInstance(ctx);
|
|
15202
|
+
Promise.resolve().then(() => Promise.resolve().then(cleanup));
|
|
14732
15203
|
throw e;
|
|
14733
15204
|
});
|
|
14734
15205
|
}
|
|
14735
|
-
return [
|
|
15206
|
+
return [
|
|
15207
|
+
awaitable,
|
|
15208
|
+
() => {
|
|
15209
|
+
setCurrentInstance(ctx);
|
|
15210
|
+
Promise.resolve().then(cleanup);
|
|
15211
|
+
}
|
|
15212
|
+
];
|
|
14736
15213
|
}
|
|
14737
15214
|
|
|
14738
15215
|
function createDuplicateChecker() {
|
|
@@ -15800,7 +16277,7 @@ function shouldUpdateComponent(prevVNode, nextVNode, optimized) {
|
|
|
15800
16277
|
const dynamicProps = nextVNode.dynamicProps;
|
|
15801
16278
|
for (let i = 0; i < dynamicProps.length; i++) {
|
|
15802
16279
|
const key = dynamicProps[i];
|
|
15803
|
-
if (nextProps
|
|
16280
|
+
if (hasPropValueChanged(nextProps, prevProps, key) && !isEmitListener(emits, key)) {
|
|
15804
16281
|
return true;
|
|
15805
16282
|
}
|
|
15806
16283
|
}
|
|
@@ -15831,12 +16308,20 @@ function hasPropsChanged(prevProps, nextProps, emitsOptions) {
|
|
|
15831
16308
|
}
|
|
15832
16309
|
for (let i = 0; i < nextKeys.length; i++) {
|
|
15833
16310
|
const key = nextKeys[i];
|
|
15834
|
-
if (nextProps
|
|
16311
|
+
if (hasPropValueChanged(nextProps, prevProps, key) && !isEmitListener(emitsOptions, key)) {
|
|
15835
16312
|
return true;
|
|
15836
16313
|
}
|
|
15837
16314
|
}
|
|
15838
16315
|
return false;
|
|
15839
16316
|
}
|
|
16317
|
+
function hasPropValueChanged(nextProps, prevProps, key) {
|
|
16318
|
+
const nextProp = nextProps[key];
|
|
16319
|
+
const prevProp = prevProps[key];
|
|
16320
|
+
if (key === "style" && (0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.isObject)(nextProp) && (0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.isObject)(prevProp)) {
|
|
16321
|
+
return !(0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.looseEqual)(nextProp, prevProp);
|
|
16322
|
+
}
|
|
16323
|
+
return nextProp !== prevProp;
|
|
16324
|
+
}
|
|
15840
16325
|
function updateHOCHostEl({ vnode, parent }, el) {
|
|
15841
16326
|
while (parent) {
|
|
15842
16327
|
const root = parent.subTree;
|
|
@@ -16567,15 +17052,7 @@ function baseCreateRenderer(options, createHydrationFns) {
|
|
|
16567
17052
|
} else {
|
|
16568
17053
|
const el = n2.el = n1.el;
|
|
16569
17054
|
if (n2.children !== n1.children) {
|
|
16570
|
-
|
|
16571
|
-
const childNodes = container.childNodes;
|
|
16572
|
-
const newChild = hostCreateText(n2.children);
|
|
16573
|
-
const oldChild = childNodes[n2.__elIndex = n1.__elIndex];
|
|
16574
|
-
hostInsert(newChild, container, oldChild);
|
|
16575
|
-
hostRemove(oldChild);
|
|
16576
|
-
} else {
|
|
16577
|
-
hostSetText(el, n2.children);
|
|
16578
|
-
}
|
|
17055
|
+
hostSetText(el, n2.children);
|
|
16579
17056
|
}
|
|
16580
17057
|
}
|
|
16581
17058
|
};
|
|
@@ -16651,7 +17128,7 @@ function baseCreateRenderer(options, createHydrationFns) {
|
|
|
16651
17128
|
optimized
|
|
16652
17129
|
);
|
|
16653
17130
|
} else {
|
|
16654
|
-
const customElement =
|
|
17131
|
+
const customElement = n1.el && n1.el._isVueCE ? n1.el : null;
|
|
16655
17132
|
try {
|
|
16656
17133
|
if (customElement) {
|
|
16657
17134
|
customElement._beginPatch();
|
|
@@ -17132,8 +17609,7 @@ function baseCreateRenderer(options, createHydrationFns) {
|
|
|
17132
17609
|
hydrateSubTree();
|
|
17133
17610
|
}
|
|
17134
17611
|
} else {
|
|
17135
|
-
if (root.ce &&
|
|
17136
|
-
root.ce._def.shadowRoot !== false) {
|
|
17612
|
+
if (root.ce && root.ce._hasShadowRoot()) {
|
|
17137
17613
|
root.ce._injectChildStyle(type);
|
|
17138
17614
|
}
|
|
17139
17615
|
if (true) {
|
|
@@ -17188,9 +17664,9 @@ function baseCreateRenderer(options, createHydrationFns) {
|
|
|
17188
17664
|
updateComponentPreRender(instance, next, optimized);
|
|
17189
17665
|
}
|
|
17190
17666
|
nonHydratedAsyncRoot.asyncDep.then(() => {
|
|
17191
|
-
|
|
17192
|
-
|
|
17193
|
-
}
|
|
17667
|
+
queuePostRenderEffect(() => {
|
|
17668
|
+
if (!instance.isUnmounted) update();
|
|
17669
|
+
}, parentSuspense);
|
|
17194
17670
|
});
|
|
17195
17671
|
return;
|
|
17196
17672
|
}
|
|
@@ -17887,12 +18363,10 @@ function traverseStaticChildren(n1, n2, shallow = false) {
|
|
|
17887
18363
|
traverseStaticChildren(c1, c2);
|
|
17888
18364
|
}
|
|
17889
18365
|
if (c2.type === Text) {
|
|
17890
|
-
if (c2.patchFlag
|
|
17891
|
-
c2
|
|
17892
|
-
} else {
|
|
17893
|
-
c2.__elIndex = i + // take fragment start anchor into account
|
|
17894
|
-
(n1.type === Fragment ? 1 : 0);
|
|
18366
|
+
if (c2.patchFlag === -1) {
|
|
18367
|
+
c2 = ch2[i] = cloneIfMounted(c2);
|
|
17895
18368
|
}
|
|
18369
|
+
c2.el = c1.el;
|
|
17896
18370
|
}
|
|
17897
18371
|
if (c2.type === Comment && !c2.el) {
|
|
17898
18372
|
c2.el = c1.el;
|
|
@@ -19620,7 +20094,7 @@ function isMemoSame(cached, memo) {
|
|
|
19620
20094
|
return true;
|
|
19621
20095
|
}
|
|
19622
20096
|
|
|
19623
|
-
const version = "3.5.
|
|
20097
|
+
const version = "3.5.29";
|
|
19624
20098
|
const warn = true ? warn$1 : 0;
|
|
19625
20099
|
const ErrorTypeStrings = ErrorTypeStrings$1 ;
|
|
19626
20100
|
const devtools = true ? devtools$1 : 0;
|
|
@@ -19831,7 +20305,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
19831
20305
|
/* harmony import */ var _vue_runtime_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @vue/runtime-core */ "./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js");
|
|
19832
20306
|
/* harmony import */ var _vue_runtime_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @vue/shared */ "./node_modules/@vue/shared/dist/shared.esm-bundler.js");
|
|
19833
20307
|
/**
|
|
19834
|
-
* @vue/runtime-dom v3.5.
|
|
20308
|
+
* @vue/runtime-dom v3.5.29
|
|
19835
20309
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
19836
20310
|
* @license MIT
|
|
19837
20311
|
**/
|
|
@@ -21091,6 +21565,12 @@ class VueElement extends BaseClass {
|
|
|
21091
21565
|
this._update();
|
|
21092
21566
|
}
|
|
21093
21567
|
}
|
|
21568
|
+
/**
|
|
21569
|
+
* @internal
|
|
21570
|
+
*/
|
|
21571
|
+
_hasShadowRoot() {
|
|
21572
|
+
return this._def.shadowRoot !== false;
|
|
21573
|
+
}
|
|
21094
21574
|
/**
|
|
21095
21575
|
* @internal
|
|
21096
21576
|
*/
|
|
@@ -21225,10 +21705,7 @@ const TransitionGroupImpl = /* @__PURE__ */ decorate({
|
|
|
21225
21705
|
instance
|
|
21226
21706
|
)
|
|
21227
21707
|
);
|
|
21228
|
-
positionMap.set(child,
|
|
21229
|
-
left: child.el.offsetLeft,
|
|
21230
|
-
top: child.el.offsetTop
|
|
21231
|
-
});
|
|
21708
|
+
positionMap.set(child, getPosition(child.el));
|
|
21232
21709
|
}
|
|
21233
21710
|
}
|
|
21234
21711
|
}
|
|
@@ -21259,10 +21736,7 @@ function callPendingCbs(c) {
|
|
|
21259
21736
|
}
|
|
21260
21737
|
}
|
|
21261
21738
|
function recordPosition(c) {
|
|
21262
|
-
newPositionMap.set(c,
|
|
21263
|
-
left: c.el.offsetLeft,
|
|
21264
|
-
top: c.el.offsetTop
|
|
21265
|
-
});
|
|
21739
|
+
newPositionMap.set(c, getPosition(c.el));
|
|
21266
21740
|
}
|
|
21267
21741
|
function applyTranslation(c) {
|
|
21268
21742
|
const oldPos = positionMap.get(c);
|
|
@@ -21270,12 +21744,29 @@ function applyTranslation(c) {
|
|
|
21270
21744
|
const dx = oldPos.left - newPos.left;
|
|
21271
21745
|
const dy = oldPos.top - newPos.top;
|
|
21272
21746
|
if (dx || dy) {
|
|
21273
|
-
const
|
|
21274
|
-
s
|
|
21747
|
+
const el = c.el;
|
|
21748
|
+
const s = el.style;
|
|
21749
|
+
const rect = el.getBoundingClientRect();
|
|
21750
|
+
let scaleX = 1;
|
|
21751
|
+
let scaleY = 1;
|
|
21752
|
+
if (el.offsetWidth) scaleX = rect.width / el.offsetWidth;
|
|
21753
|
+
if (el.offsetHeight) scaleY = rect.height / el.offsetHeight;
|
|
21754
|
+
if (!Number.isFinite(scaleX) || scaleX === 0) scaleX = 1;
|
|
21755
|
+
if (!Number.isFinite(scaleY) || scaleY === 0) scaleY = 1;
|
|
21756
|
+
if (Math.abs(scaleX - 1) < 0.01) scaleX = 1;
|
|
21757
|
+
if (Math.abs(scaleY - 1) < 0.01) scaleY = 1;
|
|
21758
|
+
s.transform = s.webkitTransform = `translate(${dx / scaleX}px,${dy / scaleY}px)`;
|
|
21275
21759
|
s.transitionDuration = "0s";
|
|
21276
21760
|
return c;
|
|
21277
21761
|
}
|
|
21278
21762
|
}
|
|
21763
|
+
function getPosition(el) {
|
|
21764
|
+
const rect = el.getBoundingClientRect();
|
|
21765
|
+
return {
|
|
21766
|
+
left: rect.left,
|
|
21767
|
+
top: rect.top
|
|
21768
|
+
};
|
|
21769
|
+
}
|
|
21279
21770
|
function hasCSSTransform(el, root, moveClass) {
|
|
21280
21771
|
const clone = el.cloneNode();
|
|
21281
21772
|
const _vtc = el[vtcKey];
|
|
@@ -21586,6 +22077,7 @@ const modifierGuards = {
|
|
|
21586
22077
|
exact: (e, modifiers) => systemModifiers.some((m) => e[`${m}Key`] && !modifiers.includes(m))
|
|
21587
22078
|
};
|
|
21588
22079
|
const withModifiers = (fn, modifiers) => {
|
|
22080
|
+
if (!fn) return fn;
|
|
21589
22081
|
const cache = fn._withMods || (fn._withMods = {});
|
|
21590
22082
|
const cacheKey = modifiers.join(".");
|
|
21591
22083
|
return cache[cacheKey] || (cache[cacheKey] = ((event, ...args) => {
|
|
@@ -21837,7 +22329,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
21837
22329
|
/* harmony export */ toTypeString: () => (/* binding */ toTypeString)
|
|
21838
22330
|
/* harmony export */ });
|
|
21839
22331
|
/**
|
|
21840
|
-
* @vue/shared v3.5.
|
|
22332
|
+
* @vue/shared v3.5.29
|
|
21841
22333
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
21842
22334
|
* @license MIT
|
|
21843
22335
|
**/
|
|
@@ -23084,7 +23576,7 @@ module.exports = {
|
|
|
23084
23576
|
"use strict";
|
|
23085
23577
|
|
|
23086
23578
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
23087
|
-
exports.toUTF8 = exports.getBigInt64LE = exports.getFloat64LE = exports.getInt32LE = exports.UUID = exports.Timestamp = exports.serialize = exports.ObjectId = exports.MinKey = exports.MaxKey = exports.Long = exports.Int32 = exports.EJSON = exports.Double = exports.deserialize = exports.Decimal128 = exports.DBRef = exports.Code = exports.calculateObjectSize = exports.BSONType = exports.BSONSymbol = exports.BSONRegExp = exports.BSONError = exports.BSON = exports.Binary = void 0;
|
|
23579
|
+
exports.toUTF8 = exports.getBigInt64LE = exports.getFloat64LE = exports.getInt32LE = exports.UUID = exports.Timestamp = exports.serialize = exports.ObjectId = exports.NumberUtils = exports.MinKey = exports.MaxKey = exports.Long = exports.Int32 = exports.EJSON = exports.Double = exports.deserialize = exports.Decimal128 = exports.DBRef = exports.Code = exports.calculateObjectSize = exports.BSONType = exports.BSONSymbol = exports.BSONRegExp = exports.BSONError = exports.BSON = exports.Binary = void 0;
|
|
23088
23580
|
exports.parseToElementsToArray = parseToElementsToArray;
|
|
23089
23581
|
exports.pluckBSONSerializeOptions = pluckBSONSerializeOptions;
|
|
23090
23582
|
exports.resolveBSONOptions = resolveBSONOptions;
|
|
@@ -23109,6 +23601,7 @@ Object.defineProperty(exports, "Int32", ({ enumerable: true, get: function () {
|
|
|
23109
23601
|
Object.defineProperty(exports, "Long", ({ enumerable: true, get: function () { return bson_2.Long; } }));
|
|
23110
23602
|
Object.defineProperty(exports, "MaxKey", ({ enumerable: true, get: function () { return bson_2.MaxKey; } }));
|
|
23111
23603
|
Object.defineProperty(exports, "MinKey", ({ enumerable: true, get: function () { return bson_2.MinKey; } }));
|
|
23604
|
+
Object.defineProperty(exports, "NumberUtils", ({ enumerable: true, get: function () { return bson_2.NumberUtils; } }));
|
|
23112
23605
|
Object.defineProperty(exports, "ObjectId", ({ enumerable: true, get: function () { return bson_2.ObjectId; } }));
|
|
23113
23606
|
Object.defineProperty(exports, "serialize", ({ enumerable: true, get: function () { return bson_2.serialize; } }));
|
|
23114
23607
|
Object.defineProperty(exports, "Timestamp", ({ enumerable: true, get: function () { return bson_2.Timestamp; } }));
|
|
@@ -23774,7 +24267,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
23774
24267
|
/* harmony import */ var _vue_runtime_dom__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @vue/runtime-dom */ "./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js");
|
|
23775
24268
|
/* harmony import */ var _vue_runtime_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @vue/runtime-dom */ "./node_modules/@vue/runtime-dom/dist/runtime-dom.esm-bundler.js");
|
|
23776
24269
|
/**
|
|
23777
|
-
* vue v3.5.
|
|
24270
|
+
* vue v3.5.29
|
|
23778
24271
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
23779
24272
|
* @license MIT
|
|
23780
24273
|
**/
|
|
@@ -24928,7 +25421,7 @@ module.exports = "<div class=\"relative flex items-start\" :class=\"{'justify-en
|
|
|
24928
25421
|
(module) {
|
|
24929
25422
|
|
|
24930
25423
|
"use strict";
|
|
24931
|
-
module.exports = "<div class=\"flex\" style=\"height: calc(100vh - 55px); height: calc(100dvh - 55px)\">\n <
|
|
25424
|
+
module.exports = "<div class=\"flex\" style=\"height: calc(100vh - 55px); height: calc(100dvh - 55px)\">\n <button\n type=\"button\"\n class=\"fixed top-[65px] left-0 cursor-pointer bg-gray-100 rounded-r-md z-10 p-1 lg:hidden\"\n @click=\"hideSidebar = false\"\n v-show=\"hideSidebar !== false\"\n aria-label=\"Open chat history\"\n title=\"Open chat history\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 -960 960 960\" class=\"w-5 h-5\" fill=\"#5f6368\"><path d=\"M360-120v-720h80v720h-80Zm160-160v-400l200 200-200 200Z\"/></svg>\n </button>\n <button\n class=\"fixed top-[65px] right-4 z-10 p-2 rounded-md shadow bg-white\"\n :class=\"hasWorkspace ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 cursor-not-allowed bg-gray-50'\"\n @click=\"toggleShareThread\"\n :disabled=\"!hasWorkspace || !chatThreadId || sharingThread\"\n aria-label=\"Share thread with workspace\"\n title=\"Share thread with workspace\"\n >\n <svg v-if=\"hasWorkspace\" xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\"><path d=\"M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7a2.48 2.48 0 0 0 0-1.39l7.02-4.11a2.5 2.5 0 1 0-.87-1.37L8.04 9.94a2.5 2.5 0 1 0 0 4.12l7.12 4.16a2.5 2.5 0 1 0 .84-1.34l-7.05-4.12c-.04-.02-.08-.05-.11-.07a2.48 2.48 0 0 0 0-1.39c.03-.02.07-.04.11-.07l7.11-4.16c.52.47 1.2.76 1.94.76a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0-1.94.94L7.97 8.43a2.5 2.5 0 1 0 0 7.14l9.09 5.3c.52-.47 1.2-.76 1.94-.76a2.5 2.5 0 1 0 0-5z\"/></svg>\n <svg v-else xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\"><path d=\"M12 1a5 5 0 00-5 5v3H6a2 2 0 00-2 2v9a2 2 0 002 2h12a2 2 0 002-2v-9a2 2 0 00-2-2h-1V6a5 5 0 00-5-5zm-3 8V6a3 3 0 016 0v3H9zm9 2v9H6v-9h12z\"/></svg>\n </button>\n <!-- Sidebar: Chat Threads -->\n <aside\n class=\"bg-white border-r overflow-y-auto overflow-x-hidden h-full transition-transform duration-300 ease-in-out z-20 w-64 fixed lg:relative\"\n :class=\"hideSidebar === false ? 'translate-x-0' : hideSidebar === true ? '-translate-x-full lg:hidden' : '-translate-x-full lg:translate-x-0'\"\n style=\"z-index: 10000\">\n <div class=\"flex items-center border-b border-gray-100 w-64 overflow-x-hidden\">\n <div class=\"p-1 ml-2 font-bold\">Chat Threads</div>\n <button\n @click=\"hideSidebar = true\"\n class=\"ml-auto mr-2 p-2 rounded hover:bg-gray-200 focus:outline-none lg:hidden\"\n aria-label=\"Close sidebar\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"currentColor\"><path d=\"M660-320v-320L500-480l160 160ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm120-80v-560H200v560h120Zm80 0h360v-560H400v560Zm-80 0H200h120Z\"/></svg>\n </button>\n </div>\n <div class=\"p-4 w-64\">\n <async-button\n @click=\"createNewThread\"\n class=\"w-full bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700\"\n >\n Create New Thread\n </async-button>\n </div>\n <div v-if=\"status === 'loaded' && chatThreads.length === 0\" class=\"p-4 text-sm text-gray-700\">\n No threads yet\n </div>\n <ul v-if=\"status === 'loaded'\" class=\"w-full\">\n <li\n v-for=\"thread in chatThreads\"\n :key=\"thread._id\"\n @click=\"selectThread(thread._id)\"\n class=\"w-full p-2 hover:bg-ultramarine-100 cursor-pointer text-sm text-gray-700\"\n :class=\"{ 'bg-ultramarine-200 text-gray-900': thread._id === chatThreadId }\"\n >\n {{ thread.title || 'Untitled Thread' }}\n </li>\n </ul>\n </aside>\n\n <!-- Main Chat Area -->\n <main class=\"flex-1 flex flex-col bg-slate-50\">\n <div class=\"flex-1 overflow-y-auto p-6 space-y-4\" ref=\"messagesContainer\">\n <div v-if=\"chatMessages?.length === 0\">\n <div class=\"flex items-center w-full h-full justify-center py-3 mb-4\">\n <p class=\"mx-4 font-bold text-gray-900\">\n Ask Mongoose Studio to analyze your data or generate a script\n </p>\n </div>\n </div>\n <ul role=\"list\" class=\"space-y-4\" v-else>\n <li v-for=\"message in chatMessages\" :key=\"message._id\">\n <chat-message :message=\"message\" :target-dashboard-id=\"currentThread?.dashboardId\"></chat-message>\n </li>\n </ul>\n </div>\n\n\n <!-- Input Area -->\n <div class=\"border-t p-4\">\n <form @submit.prevent=\"sendMessage\" :disabled=\"sendingMessage\" class=\"flex gap-2 items-end justify-end\">\n <textarea\n v-model=\"newMessage\"\n :placeholder=\"sendingMessage ? 'Sending...' : 'Ask about your data, generate a query, or build a chart…'\"\n class=\"flex-1 border rounded px-4 py-2 resize-none overflow-y-auto shadow-sm\"\n :disabled=\"sendingMessage\"\n rows=\"2\"\n ref=\"messageInput\"\n @input=\"adjustTextareaHeight\"\n @keydown.enter.exact.prevent=\"handleEnter\"\n ></textarea>\n <button class=\"bg-blue-600 text-white px-4 h-[42px] rounded disabled:bg-gray-600\" :disabled=\"sendingMessage\">\n <svg v-if=\"sendingMessage\" style=\"height: 1em\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <g>\n <circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" opacity=\"0.3\" />\n <path d=\"M12 2a10 10 0 0 1 10 10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\">\n <animateTransform attributeName=\"transform\" type=\"rotate\" from=\"0 12 12\" to=\"360 12 12\" dur=\"1s\" repeatCount=\"indefinite\" />\n </path>\n </g>\n </svg>\n <span v-else>Send</span>\n </button>\n </form>\n </div>\n </main>\n</div>\n";
|
|
24932
25425
|
|
|
24933
25426
|
/***/ },
|
|
24934
25427
|
|
|
@@ -25214,7 +25707,7 @@ module.exports = ".document .document-menu {\n display: flex;\n position: stic
|
|
|
25214
25707
|
(module) {
|
|
25215
25708
|
|
|
25216
25709
|
"use strict";
|
|
25217
|
-
module.exports = "<div class=\"document px-1 pt-4 pb-16 md:px-0 bg-slate-50 w-full\">\n <div class=\"max-w-7xl mx-auto\">\n <div class=\"flex gap-4 items-center sticky top-0 z-50 bg-white p-4 border-b border-gray-200 shadow-sm\">\n <div class=\"font-bold overflow-hidden text-ellipsis\">{{model}}: {{documentId}}</div>\n <div class=\"flex grow\">\n <button\n @click=\"viewMode = 'fields'\"\n :class=\"viewMode === 'fields'\n ? 'bg-blue-600 text-white z-10'\n : 'bg-gray-200 text-gray-700 hover:bg-gray-300'\"\n class=\"px-2 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 flex items-center gap-2 border border-gray-300 border-r-0 rounded-l-lg rounded-r-none\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 6h16M4 10h16M4 14h16M4 18h16\"></path>\n </svg>\n Fields\n </button>\n <button\n @click=\"viewMode = 'json'\"\n :class=\"viewMode === 'json'\n ? 'bg-blue-600 text-white z-10'\n : 'bg-gray-200 text-gray-700 hover:bg-gray-300'\"\n class=\"px-2 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 flex items-center gap-2 border border-gray-300 rounded-r-lg rounded-l-none\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4\"></path>\n </svg>\n JSON\n </button>\n </div>\n\n <div class=\"hidden md:flex items-center gap-3 text-sm text-slate-600\">\n <div class=\"text-right leading-tight\">\n <div class=\"text-xs uppercase tracking-wide text-slate-400 flex items-center gap-2 justify-end\">\n <span>Loaded at</span>\n <span class=\"inline-flex items-center gap-1 text-[10px] font-semibold\" :class=\"autoRefreshEnabled ? 'text-forest-green-600' : 'text-slate-400'\">\n <span class=\"inline-block h-1.5 w-1.5 rounded-full\" :class=\"autoRefreshEnabled ? 'bg-forest-green-500' : 'bg-slate-300'\"></span>\n </span>\n </div>\n <div class=\"font-medium text-slate-700\">{{lastUpdatedLabel}}</div>\n </div>\n </div>\n\n <div class=\"gap-2 hidden md:flex items-center\">\n <button\n v-if=\"!editting\"\n @click=\"editting = true\"\n :disabled=\"!canEdit\"\n :class=\"{'cursor-not-allowed opacity-50': !canEdit}\"\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\n <!-- 3-dot menu -->\n <div class=\"relative\">\n <button\n @click=\"desktopMenuOpen = !desktopMenuOpen\"\n type=\"button\"\n class=\"inline-flex items-center justify-center rounded-md bg-gray-200 px-2.5 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500\"\n aria-expanded=\"desktopMenuOpen\"\n aria-label=\"More options\"\n >\n <svg class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"5\" r=\"2\"></circle>\n <circle cx=\"12\" cy=\"12\" r=\"2\"></circle>\n <circle cx=\"12\" cy=\"19\" r=\"2\"></circle>\n </svg>\n </button>\n <div\n v-show=\"desktopMenuOpen\"\n @click.away=\"desktopMenuOpen = false\"\n class=\"origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 z-50\"\n >\n <div class=\"py-1 flex flex-col\">\n <button\n @click=\"refreshDocument({ force: true, source: 'manual' }); desktopMenuOpen = false\"\n :disabled=\"isRefreshing\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', isRefreshing ? 'cursor-not-allowed opacity-50' : 'hover:bg-slate-100']\"\n type=\"button\"\n >\n {{isRefreshing ? 'Refreshing...' : 'Refresh'}}\n </button>\n <button\n @click=\"toggleAutoRefresh(); desktopMenuOpen = false\"\n :disabled=\"isLambda\"\n type=\"button\"\n :class=\"['flex items-center px-4 py-2 text-sm', isLambda ? 'text-gray-400 cursor-not-allowed' : 'text-gray-700 hover:bg-slate-100']\"\n :title=\"isLambda ? 'Auto-refresh only available on Express deployments' : ''\"\n >\n {{autoRefreshEnabled ? 'Disable Auto-Refresh' : 'Enable Auto-Refresh'}}\n </button>\n <button\n @click=\"addField(); desktopMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-green-100\"\n >\n Add Field\n </button>\n <button\n @click=\"copyDocument(); desktopMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-blue-100\"\n >\n Copy Document\n </button>\n <button\n @click=\"openScriptDrawer()\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-indigo-100\"\n >\n Run Script\n </button>\n <button\n @click=\"shouldShowDeleteModal=true; desktopMenuOpen = false\"\n :disabled=\"!canManipulate\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-red-100']\"\n type=\"button\"\n >\n Delete\n </button>\n <button\n @click=\"shouldShowCloneModal=true; desktopMenuOpen = false\"\n :disabled=\"!canManipulate\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-pink-100']\"\n type=\"button\"\n >\n Clone\n </button>\n </div>\n </div>\n </div>\n </div>\n <div class=\"md:hidden flex items-center\">\n <div class=\"relative\">\n <button\n @click=\"mobileMenuOpen = !mobileMenuOpen\"\n type=\"button\"\n class=\"inline-flex items-center justify-center rounded-md bg-gray-200 px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500\"\n aria-expanded=\"mobileMenuOpen\"\n aria-label=\"Open menu\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M4 6h16M4 12h16M4 18h16\"></path>\n </svg>\n </button>\n <div\n v-show=\"mobileMenuOpen\"\n @click.away=\"mobileMenuOpen = false\"\n class=\"origin-top-right absolute right-0 mt-2 w-52 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 z-50\"\n >\n <div class=\"py-1 flex flex-col\">\n <button\n v-if=\"!editting\"\n @click=\"editting = true; mobileMenuOpen = false\"\n :disabled=\"!canEdit\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canEdit ? 'cursor-not-allowed opacity-50' : 'hover:bg-ultramarine-100']\"\n type=\"button\"\n >\n Edit\n </button>\n <button\n v-if=\"editting\"\n @click=\"editting = false; mobileMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-slate-100\"\n >\n Cancel\n </button>\n <button\n v-if=\"editting\"\n :disabled=\"!canManipulate\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-green-100']\"\n @click=\"shouldShowConfirmModal=true; mobileMenuOpen = false\"\n type=\"button\"\n >\n Save\n </button>\n <button\n @click=\"refreshDocument({ force: true, source: 'manual' }); mobileMenuOpen = false\"\n :disabled=\"isRefreshing\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', isRefreshing ? 'cursor-not-allowed opacity-50' : 'hover:bg-slate-100']\"\n type=\"button\"\n >\n {{isRefreshing ? 'Refreshing...' : 'Refresh'}}\n </button>\n <button\n @click=\"toggleAutoRefresh(); mobileMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-slate-100\"\n >\n Auto-Refresh {{autoRefreshEnabled ? 'ON' : 'OFF'}}\n </button>\n <button\n @click=\"addField(); mobileMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-green-100\"\n >\n Add Field\n </button>\n <button\n @click=\"copyDocument(); mobileMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-blue-100\"\n >\n Copy Document\n </button>\n <button\n @click=\"openScriptDrawer()\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-indigo-100\"\n >\n Run Script\n </button>\n <button\n @click=\"shouldShowDeleteModal=true; mobileMenuOpen = false\"\n :disabled=\"!canManipulate\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-red-100']\"\n type=\"button\"\n >\n Delete\n </button>\n <button\n @click=\"shouldShowCloneModal=true; mobileMenuOpen = false\"\n :disabled=\"!canManipulate\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-pink-100']\"\n type=\"button\"\n >\n Clone\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div v-if=\"status === 'loaded'\">\n <document-details\n :document=\"document\"\n :schemaPaths=\"schemaPaths\"\n :virtualPaths=\"virtualPaths\"\n :editting=\"editting\"\n :changes=\"changes\"\n :invalid=\"invalid\"\n :viewMode=\"viewMode\"\n :model=\"model\"\n @add-field=\"addField\"\n @view-mode-change=\"updateViewMode\"></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=\"shouldShowDeleteModal = false;\">×</div>\n <confirm-delete @close=\"shouldShowDeleteModal = 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 <execute-script\n :visible=\"scriptDrawerOpen\"\n :model=\"model\"\n :document-id=\"documentId\"\n :editting=\"editting\"\n @close=\"closeScriptDrawer\"\n @refresh=\"handleScriptRefresh\"\n ></execute-script>\n </div>\n</div>\n";
|
|
25710
|
+
module.exports = "<div class=\"document px-1 pt-4 pb-16 md:px-0 bg-slate-50 w-full\">\n <div class=\"max-w-7xl mx-auto\">\n <div class=\"flex gap-4 items-center sticky top-0 z-50 bg-white p-4 border-b border-gray-200 shadow-sm\">\n <div class=\"font-bold overflow-hidden text-ellipsis\">{{model}}: {{documentId}}</div>\n <div class=\"flex grow\">\n <button\n @click=\"viewMode = 'fields'\"\n :class=\"viewMode === 'fields'\n ? 'bg-blue-600 text-white z-10'\n : 'bg-gray-200 text-gray-700 hover:bg-gray-300'\"\n class=\"px-2 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 flex items-center gap-2 border border-gray-300 border-r-0 rounded-l-lg rounded-r-none\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 6h16M4 10h16M4 14h16M4 18h16\"></path>\n </svg>\n Fields\n </button>\n <button\n @click=\"viewMode = 'json'\"\n :class=\"viewMode === 'json'\n ? 'bg-blue-600 text-white z-10'\n : 'bg-gray-200 text-gray-700 hover:bg-gray-300'\"\n class=\"px-2 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 flex items-center gap-2 border border-gray-300 rounded-r-lg rounded-l-none\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4\"></path>\n </svg>\n JSON\n </button>\n </div>\n\n <div class=\"hidden md:flex items-center gap-3 text-sm text-slate-600\">\n <div class=\"text-right leading-tight\">\n <div class=\"text-xs uppercase tracking-wide text-slate-400 flex items-center gap-2 justify-end\">\n <span>Loaded at</span>\n <span class=\"inline-flex items-center gap-1 text-[10px] font-semibold\" :class=\"autoRefreshEnabled ? 'text-forest-green-600' : 'text-slate-400'\">\n <span class=\"inline-block h-1.5 w-1.5 rounded-full\" :class=\"autoRefreshEnabled ? 'bg-forest-green-500' : 'bg-slate-300'\"></span>\n </span>\n </div>\n <div class=\"font-medium text-slate-700\">{{lastUpdatedLabel}}</div>\n </div>\n </div>\n\n <div class=\"gap-2 hidden md:flex items-center\">\n <button\n v-if=\"!editting\"\n @click=\"editting = true\"\n :disabled=\"!canEdit\"\n :class=\"{'cursor-not-allowed opacity-50': !canEdit}\"\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\n <!-- 3-dot menu -->\n <div class=\"relative\">\n <button\n @click=\"desktopMenuOpen = !desktopMenuOpen\"\n type=\"button\"\n class=\"inline-flex items-center justify-center rounded-md bg-gray-200 px-2.5 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500\"\n aria-expanded=\"desktopMenuOpen\"\n aria-label=\"More options\"\n >\n <svg class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"5\" r=\"2\"></circle>\n <circle cx=\"12\" cy=\"12\" r=\"2\"></circle>\n <circle cx=\"12\" cy=\"19\" r=\"2\"></circle>\n </svg>\n </button>\n <div\n v-show=\"desktopMenuOpen\"\n @click.away=\"desktopMenuOpen = false\"\n class=\"origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 z-50\"\n >\n <div class=\"py-1 flex flex-col\">\n <button\n @click=\"refreshDocument({ force: true, source: 'manual' }); desktopMenuOpen = false\"\n :disabled=\"isRefreshing\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', isRefreshing ? 'cursor-not-allowed opacity-50' : 'hover:bg-slate-100']\"\n type=\"button\"\n >\n {{isRefreshing ? 'Refreshing...' : 'Refresh'}}\n </button>\n <button\n @click=\"toggleAutoRefresh(); desktopMenuOpen = false\"\n :disabled=\"isLambda\"\n type=\"button\"\n :class=\"['flex items-center px-4 py-2 text-sm', isLambda ? 'text-gray-400 cursor-not-allowed' : 'text-gray-700 hover:bg-slate-100']\"\n :title=\"isLambda ? 'Auto-refresh only available on Express deployments' : ''\"\n >\n {{autoRefreshEnabled ? 'Disable Auto-Refresh' : 'Enable Auto-Refresh'}}\n </button>\n <button\n @click=\"addField(); desktopMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-green-100\"\n >\n Add Field\n </button>\n <button\n @click=\"copyDocument(); desktopMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-blue-100\"\n >\n Copy Document\n </button>\n <button\n @click=\"openScriptDrawer()\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-indigo-100\"\n >\n Run Script\n </button>\n <button\n @click=\"shouldShowDeleteModal=true; desktopMenuOpen = false\"\n :disabled=\"!canManipulate\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-red-100']\"\n type=\"button\"\n >\n Delete\n </button>\n <button\n @click=\"shouldShowCloneModal=true; desktopMenuOpen = false\"\n :disabled=\"!canManipulate\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-pink-100']\"\n type=\"button\"\n >\n Clone\n </button>\n </div>\n </div>\n </div>\n </div>\n <div class=\"md:hidden flex items-center\">\n <div class=\"relative\">\n <button\n @click=\"mobileMenuOpen = !mobileMenuOpen\"\n type=\"button\"\n class=\"inline-flex items-center justify-center rounded-md bg-gray-200 px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500\"\n aria-expanded=\"mobileMenuOpen\"\n aria-label=\"Open menu\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M4 6h16M4 12h16M4 18h16\"></path>\n </svg>\n </button>\n <div\n v-show=\"mobileMenuOpen\"\n @click.away=\"mobileMenuOpen = false\"\n class=\"origin-top-right absolute right-0 mt-2 w-52 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 z-50\"\n >\n <div class=\"py-1 flex flex-col\">\n <button\n v-if=\"!editting\"\n @click=\"editting = true; mobileMenuOpen = false\"\n :disabled=\"!canEdit\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canEdit ? 'cursor-not-allowed opacity-50' : 'hover:bg-ultramarine-100']\"\n type=\"button\"\n >\n Edit\n </button>\n <button\n v-if=\"editting\"\n @click=\"editting = false; mobileMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-slate-100\"\n >\n Cancel\n </button>\n <button\n v-if=\"editting\"\n :disabled=\"!canManipulate\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-green-100']\"\n @click=\"shouldShowConfirmModal=true; mobileMenuOpen = false\"\n type=\"button\"\n >\n Save\n </button>\n <button\n @click=\"refreshDocument({ force: true, source: 'manual' }); mobileMenuOpen = false\"\n :disabled=\"isRefreshing\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', isRefreshing ? 'cursor-not-allowed opacity-50' : 'hover:bg-slate-100']\"\n type=\"button\"\n >\n {{isRefreshing ? 'Refreshing...' : 'Refresh'}}\n </button>\n <button\n @click=\"toggleAutoRefresh(); mobileMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-slate-100\"\n >\n Auto-Refresh {{autoRefreshEnabled ? 'ON' : 'OFF'}}\n </button>\n <button\n @click=\"addField(); mobileMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-green-100\"\n >\n Add Field\n </button>\n <button\n @click=\"copyDocument(); mobileMenuOpen = false\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-blue-100\"\n >\n Copy Document\n </button>\n <button\n @click=\"openScriptDrawer()\"\n type=\"button\"\n class=\"flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-indigo-100\"\n >\n Run Script\n </button>\n <button\n @click=\"shouldShowDeleteModal=true; mobileMenuOpen = false\"\n :disabled=\"!canManipulate\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-red-100']\"\n type=\"button\"\n >\n Delete\n </button>\n <button\n @click=\"shouldShowCloneModal=true; mobileMenuOpen = false\"\n :disabled=\"!canManipulate\"\n :class=\"['flex items-center px-4 py-2 text-sm text-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-pink-100']\"\n type=\"button\"\n >\n Clone\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div v-if=\"status === 'loaded'\">\n <document-details\n :document=\"document\"\n :schemaPaths=\"schemaPaths\"\n :virtualPaths=\"virtualPaths\"\n :editting=\"editting\"\n :changes=\"changes\"\n :invalid=\"invalid\"\n :viewMode=\"viewMode\"\n :model=\"model\"\n @add-field=\"addField\"\n @view-mode-change=\"updateViewMode\"></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=\"shouldShowDeleteModal = false;\">×</div>\n <confirm-delete @close=\"shouldShowDeleteModal = 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 <execute-script\n :visible=\"scriptDrawerOpen\"\n :model=\"model\"\n :document-id=\"documentId\"\n :editting=\"editting\"\n @close=\"closeScriptDrawer\"\n @refresh=\"handleScriptRefresh\"\n ></execute-script>\n <div\n v-if=\"keyboardShortcuts.length > 0\"\n class=\"fixed bottom-4 left-4 z-40 group\"\n >\n <button\n type=\"button\"\n aria-label=\"Keyboard shortcuts\"\n title=\"Keyboard shortcuts\"\n class=\"rounded-full border border-slate-300 bg-white p-2 text-slate-700 shadow-sm transition-colors hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-ultramarine-500\"\n >\n <svg class=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <rect x=\"2.5\" y=\"6.5\" width=\"19\" height=\"11\" rx=\"2\" stroke-width=\"1.5\"></rect>\n <path d=\"M6 10.5h1.5M9 10.5h1.5M12 10.5h1.5M15 10.5h1.5M18 10.5h.01M6 13.5h1.5M9 13.5h6M16.5 13.5h1.5\" stroke-width=\"1.5\" stroke-linecap=\"round\"></path>\n </svg>\n </button>\n <div class=\"pointer-events-none absolute left-0 bottom-full mb-2 min-w-[220px] translate-y-1 rounded-lg bg-slate-900 px-3 py-2.5 text-slate-200 opacity-0 shadow-xl transition-all duration-150 group-hover:pointer-events-auto group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:translate-y-0 group-focus-within:opacity-100\">\n <div\n v-for=\"shortcut in keyboardShortcuts\"\n :key=\"shortcut.command + shortcut.description\"\n class=\"flex items-center justify-between gap-3 text-xs\"\n >\n <span class=\"font-mono font-semibold text-slate-50\">{{shortcut.command}}</span>\n <span class=\"text-slate-300\">{{shortcut.description}}</span>\n </div>\n </div>\n </div>\n </div>\n</div>\n";
|
|
25218
25711
|
|
|
25219
25712
|
/***/ },
|
|
25220
25713
|
|
|
@@ -25522,7 +26015,7 @@ module.exports = ".models {\n position: relative;\n display: flex;\n flex-dir
|
|
|
25522
26015
|
(module) {
|
|
25523
26016
|
|
|
25524
26017
|
"use strict";
|
|
25525
|
-
module.exports = "<div class=\"models flex\" style=\"height: calc(100vh - 55px); height: calc(100dvh - 55px)\">\n <div class=\"fixed top-[65px] cursor-pointer bg-gray-100 rounded-r-md z-10\" @click=\"hideSidebar = false\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"#5f6368\"><path d=\"M360-120v-720h80v720h-80Zm160-160v-400l200 200-200 200Z\"/></svg>\n </div>\n <aside class=\"bg-white border-r overflow-y-auto overflow-x-hidden h-full transition-all duration-300 ease-in-out z-20 w-0 lg:w-48 fixed lg:relative shrink-0\" :class=\"hideSidebar === true ? '!w-0' : hideSidebar === false ? '!w-48' : ''\">\n <div class=\"flex items-center border-b border-gray-100 w-48 overflow-x-hidden\">\n <div class=\"p-1 ml-2 font-bold\">Models</div>\n <button\n @click=\"hideSidebar = true\"\n class=\"ml-auto mr-2 p-2 rounded hover:bg-gray-200 focus:outline-none\"\n aria-label=\"Close sidebar\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"currentColor\"><path d=\"M660-320v-320L500-480l160 160ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm120-80v-560H200v560h120Zm80 0h360v-560H400v560Zm-80 0H200h120Z\"/></svg>\n </button>\n </div>\n <nav class=\"flex flex-1 flex-col\">\n <ul role=\"list\" class=\"flex flex-1 flex-col gap-y-7 p-1\">\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 text-gray-700\"\n :class=\"model === currentModel ? 'bg-ultramarine-100 font-bold text-gray-900' : 'hover:bg-ultramarine-50'\">\n {{model}}\n </router-link>\n </li>\n </ul>\n </li>\n </ul>\n <div v-if=\"models.length === 0 && status === 'loaded'\" class=\"p-2 bg-red-100\">\n No models found\n </div>\n </nav>\n </aside>\n <div class=\"documents bg-slate-50\" ref=\"documentsList\">\n <div class=\"relative h-[42px]\" style=\"z-index: 1000\">\n <div class=\"documents-menu bg-slate-50\">\n <div class=\"flex flex-row items-center w-full gap-2\">\n <document-search\n ref=\"documentSearch\"\n :value=\"searchText\"\n :schema-paths=\"schemaPaths\"\n @search=\"search\"\n >\n </document-search>\n <div>\n <span v-if=\"numDocuments == null\">Loading ...</span>\n <span v-else-if=\"typeof numDocuments === 'number'\">{{documents.length}}/{{numDocuments === 1 ? numDocuments + ' document' : numDocuments + ' documents'}}</span>\n </div>\n <button\n @click=\"stagingSelect\"\n type=\"button\"\n :class=\"{ 'bg-gray-500 ring-inset ring-2 ring-gray-300 hover:bg-gray-600': selectMultiple, 'bg-ultramarine-600 hover:bg-ultramarine-500' : !selectMultiple }\"\n class=\"rounded px-2 py-2 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\"\n >\n {{ selectMultiple ? 'Cancel' : 'Select' }}\n </button>\n <button\n v-show=\"selectMultiple\"\n @click=\"shouldShowUpdateMultipleModal=true;\"\n type=\"button\"\n class=\"rounded bg-green-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\"\n >\n Update\n </button>\n <button\n @click=\"shouldShowDeleteMultipleModal=true;\"\n type=\"button\"\n v-show=\"selectMultiple\"\n class=\"rounded bg-red-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500\"\n >\n Delete\n </button>\n <div class=\"relative\" v-show=\"!selectMultiple\" ref=\"actionsMenuContainer\" @keyup.esc.prevent=\"closeActionsMenu\">\n <button\n @click=\"toggleActionsMenu\"\n type=\"button\"\n aria-label=\"More actions\"\n class=\"rounded bg-white px-2 py-2 text-sm font-semibold text-gray-700 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-5 h-5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 6.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Zm0 6a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Zm0 6a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Z\" />\n </svg>\n </button>\n <div\n v-if=\"showActionsMenu\"\n class=\"absolute right-0 mt-2 w-48 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none z-20\"\n >\n <div class=\"py-1\">\n <button\n @click=\"shouldShowExportModal = true; showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Export\n </button>\n <button\n @click=\"shouldShowCreateModal = true; showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Create\n </button>\n <button\n @click=\"openFieldSelection(); showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Projection\n </button>\n <button\n @click=\"openIndexModal\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Indexes\n </button>\n <button\n @click=\"openCollectionInfo\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Collection Info\n </button>\n <button\n @click=\"findOldestDocument\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Find oldest document\n </button>\n </div>\n </div>\n </div>\n <span class=\"isolate inline-flex rounded-md shadow-sm\">\n <button\n @click=\"setOutputType('table')\"\n type=\"button\"\n class=\"relative inline-flex items-center rounded-none rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10\"\n :class=\"outputType === 'table' ? 'bg-gray-200' : 'bg-white'\">\n <img class=\"h-5 w-5\" src=\"images/table.svg\">\n </button>\n <button\n @click=\"setOutputType('json')\"\n type=\"button\"\n class=\"relative -ml-px inline-flex items-center 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 <button\n @click=\"setOutputType('map')\"\n :disabled=\"geoJsonFields.length === 0\"\n type=\"button\"\n :title=\"geoJsonFields.length > 0 ? 'Map view' : 'No GeoJSON fields detected'\"\n class=\"relative -ml-px inline-flex items-center rounded-none rounded-r-md px-2 py-2 ring-1 ring-inset ring-gray-300 focus:z-10\"\n :class=\"[\n geoJsonFields.length === 0 ? 'text-gray-300 cursor-not-allowed bg-gray-100' : 'text-gray-400 hover:bg-gray-50',\n outputType === 'map' ? 'bg-gray-200' : (geoJsonFields.length > 0 ? 'bg-white' : '')\n ]\">\n <svg class=\"h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 6.75V15m6-6v8.25m.503 3.498 4.875-2.437c.381-.19.622-.58.622-1.006V4.82c0-.836-.88-1.38-1.628-1.006l-3.869 1.934c-.317.159-.69.159-1.006 0L9.503 3.252a1.125 1.125 0 0 0-1.006 0L3.622 5.689C3.24 5.88 3 6.27 3 6.695V19.18c0 .836.88 1.38 1.628 1.006l3.869-1.934c.317-.159.69-.159 1.006 0l4.994 2.497c.317.158.69.158 1.006 0Z\" />\n </svg>\n </button>\n </span>\n </div>\n </div>\n </div>\n <div class=\"documents-container relative\">\n <div v-if=\"error\">\n <div class=\"bg-red-100 border border-red-400 text-red-700 px-4 py-3 relative m-4 rounded-md\" role=\"alert\">\n <span class=\"block font-bold\">Error</span>\n <span class=\"block\">{{ error }}</span>\n </div>\n </div>\n <table v-else-if=\"outputType === 'table'\">\n <thead class=\"bg-slate-50\">\n <th v-for=\"path in filteredPaths\" @click=\"addPathFilter(path.path)\" class=\"cursor-pointer p-3\">\n {{path.path}}\n <span class=\"path-type\">\n ({{(path.instance || 'unknown')}})\n </span>\n <span class=\"sort-arrow\" @click=\"sortDocs(1, path.path)\">{{sortBy[path.path] == 1 ? 'X' : '↑'}}</span>\n <span class=\"sort-arrow\" @click=\"sortDocs(-1, path.path)\">{{sortBy[path.path] == -1 ? 'X' : '↓'}}</span>\n </th>\n </thead>\n <tbody>\n <tr v-for=\"document in documents\" @click=\"handleDocumentClick(document, $event)\" :key=\"document._id\" class=\"bg-white hover:bg-slate-50\">\n <td v-for=\"schemaPath in filteredPaths\" class=\"p-3 cursor-pointer\" :class=\"{ 'bg-blue-200': selectedDocuments.some(x => x._id.toString() === document._id.toString()) }\">\n <component\n :is=\"getComponentForPath(schemaPath)\"\n :value=\"getValueForPath(document, schemaPath.path)\"\n :allude=\"getReferenceModel(schemaPath)\">\n </component>\n </td>\n </tr>\n </tbody>\n </table>\n <div v-else-if=\"outputType === 'json'\" class=\"flex flex-col space-y-2 p-1 mt-1\">\n <div\n v-for=\"document in documents\"\n :key=\"document._id\"\n @click=\"handleDocumentContainerClick(document, $event)\"\n :class=\"[\n 'group relative transition-colors rounded-md border border-slate-100',\n selectedDocuments.some(x => x._id.toString() === document._id.toString()) ? 'bg-blue-200' : 'hover:shadow-sm hover:border-slate-300 bg-white'\n ]\"\n >\n <button\n type=\"button\"\n class=\"absolute top-2 right-2 z-10 inline-flex items-center rounded bg-ultramarine-600 px-2 py-1 text-xs font-semibold text-white shadow-sm transition-opacity duration-150 opacity-0 group-hover:opacity-100 focus-visible:opacity-100 hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\"\n @click.stop=\"openDocument(document)\"\n >\n Open this Document\n </button>\n <list-json :value=\"filterDocument(document)\" :references=\"referenceMap\">\n </list-json>\n </div>\n </div>\n <div v-else-if=\"outputType === 'map'\" class=\"flex flex-col h-full\">\n <div class=\"p-2 bg-white border-b flex items-center gap-2\">\n <label class=\"text-sm font-medium text-gray-700\">GeoJSON Field:</label>\n <select\n :value=\"selectedGeoField\"\n @change=\"setSelectedGeoField($event.target.value)\"\n class=\"rounded-md border border-gray-300 py-1 px-2 text-sm focus:border-ultramarine-500 focus:ring-ultramarine-500\"\n >\n <option v-for=\"field in geoJsonFields\" :key=\"field.path\" :value=\"field.path\">\n {{ field.label }}\n </option>\n </select>\n <async-button\n @click=\"loadMoreDocuments\"\n :disabled=\"loadedAllDocs\"\n type=\"button\"\n class=\"rounded px-2 py-1 text-xs font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\"\n :class=\"loadedAllDocs ? 'bg-gray-400 cursor-not-allowed' : 'bg-ultramarine-600 hover:bg-ultramarine-500'\"\n >\n Load more\n </async-button>\n </div>\n <div class=\"flex-1 min-h-[400px]\" ref=\"modelsMap\"></div>\n </div>\n <div v-if=\"status === 'loading'\" class=\"loader\">\n <img src=\"images/loader.gif\">\n </div>\n </div>\n </div>\n <modal v-if=\"shouldShowExportModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowExportModal = false\">×</div>\n <export-query-results\n :schemaPaths=\"schemaPaths\"\n :search-text=\"searchText\"\n :currentModel=\"currentModel\"\n @done=\"shouldShowExportModal = false\">\n </export-query-results>\n </template>\n </modal>\n <modal v-if=\"shouldShowIndexModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowIndexModal = false\">×</div>\n <div class=\"text-xl font-bold mb-2\">Indexes</div>\n <div v-for=\"index in mongoDBIndexes\" class=\"w-full flex items-center\">\n <div class=\"grow shrink text-left flex justify-between items-center\" v-if=\"index.name != '_id_'\">\n <div>\n <div class=\"font-bold flex items-center gap-2\">\n <div>{{ index.name }}</div>\n <div v-if=\"isTTLIndex(index)\" class=\"rounded-full bg-ultramarine-100 px-2 py-0.5 text-xs font-semibold text-ultramarine-700\">\n TTL: {{ formatTTL(index.expireAfterSeconds) }}\n </div>\n </div>\n <div class=\"text-sm font-mono\">{{ JSON.stringify(index.key) }}</div>\n </div>\n <div>\n <async-button\n type=\"button\"\n @click=\"dropIndex(index.name)\"\n class=\"rounded-md bg-valencia-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-valencia-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600 disabled:bg-gray-400 disabled:cursor-not-allowed\">\n Drop\n </async-button>\n </div>\n </div>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowCollectionInfoModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowCollectionInfoModal = false\">×</div>\n <div class=\"text-xl font-bold mb-2\">Collection Info</div>\n <div v-if=\"!collectionInfo\" class=\"text-gray-600\">Loading collection details...</div>\n <div v-else class=\"space-y-3\">\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Documents</div>\n <div class=\"text-gray-900\">{{ formatNumber(collectionInfo.documentCount) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Indexes</div>\n <div class=\"text-gray-900\">{{ formatNumber(collectionInfo.indexCount) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Total Index Size</div>\n <div class=\"text-gray-900\">{{ formatCollectionSize(collectionInfo.totalIndexSize) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Total Storage Size</div>\n <div class=\"text-gray-900\">{{ formatCollectionSize(collectionInfo.size) }}</div>\n </div>\n <div class=\"flex flex-col gap-1\">\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Collation</div>\n <div class=\"text-gray-900\">{{ collectionInfo.hasCollation ? 'Yes' : 'No' }}</div>\n </div>\n <div v-if=\"collectionInfo.hasCollation\" class=\"rounded bg-gray-100 p-3 text-sm text-gray-800 overflow-x-auto\">\n <pre class=\"whitespace-pre-wrap\">{{ JSON.stringify(collectionInfo.collation, null, 2) }}</pre>\n </div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Capped</div>\n <div class=\"text-gray-900\">{{ collectionInfo.capped ? 'Yes' : 'No' }}</div>\n </div>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowFieldModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowFieldModal = false; selectedPaths = [...filteredPaths];\">×</div>\n <div v-for=\"(path, index) in schemaPaths\" :key=\"index\" class=\"w-5 flex items-center\">\n <input class=\"mt-0 h-4 w-4 rounded border-gray-300 text-sky-600 focus:ring-sky-600 accent-sky-600\" type=\"checkbox\" :id=\"'path.path'+index\" @change=\"addOrRemove(path)\" :value=\"path.path\" :checked=\"isSelected(path.path)\" />\n <div class=\"ml-2 text-gray-700 grow shrink text-left\">\n <label :for=\"'path.path' + index\">{{path.path}}</label>\n </div>\n </div>\n <div class=\"mt-4 flex gap-2\">\n <button type=\"button\" @click=\"filterDocuments()\" class=\"rounded-md bg-ultramarine-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600\">Filter Selection</button>\n <button type=\"button\" @click=\"selectAll()\" class=\"rounded-md bg-forest-green-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\">Select All</button>\n <button type=\"button\" @click=\"deselectAll()\" class=\"rounded-md bg-valencia-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-valencia-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600\">Deselect All</button>\n <button type=\"button\" @click=\"resetDocuments()\" class=\"rounded-md bg-gray-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\" >Cancel</button>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowCreateModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowCreateModal = false;\">×</div>\n <create-document :currentModel=\"currentModel\" :paths=\"schemaPaths\" @close=\"closeCreationModal\"></create-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowUpdateMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowUpdateMultipleModal = false;\">×</div>\n <update-document :currentModel=\"currentModel\" :document=\"selectedDocuments\" :multiple=\"true\" @update=\"updateDocuments\" @close=\"shouldShowUpdateMultipleModal=false;\"></update-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowDeleteMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowDeleteMultipleModal = false;\">×</div>\n <h2>Are you sure you want to delete {{selectedDocuments.length}} documents?</h2>\n <div>\n <list-json :value=\"selectedDocuments\"></list-json>\n </div>\n <div class=\"flex gap-4\">\n <async-button @click=\"deleteDocuments\" class=\"rounded bg-red-500 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600\">\n Confirm\n </async-button>\n <button @click=\"shouldShowDeleteMultipleModal = false;\" class=\"rounded bg-gray-400 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500\">\n Cancel\n </button>\n </div>\n </template>\n </modal>\n</div>\n";
|
|
26018
|
+
module.exports = "<div class=\"models flex\" style=\"height: calc(100vh - 55px); height: calc(100dvh - 55px)\">\n <div class=\"fixed top-[65px] cursor-pointer bg-gray-100 rounded-r-md z-10\" @click=\"hideSidebar = false\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"#5f6368\"><path d=\"M360-120v-720h80v720h-80Zm160-160v-400l200 200-200 200Z\"/></svg>\n </div>\n <aside class=\"bg-white border-r overflow-y-auto overflow-x-hidden h-full transition-all duration-300 ease-in-out z-20 w-0 lg:w-48 fixed lg:relative shrink-0\" :class=\"hideSidebar === true ? '!w-0' : hideSidebar === false ? '!w-48' : ''\">\n <div class=\"flex items-center border-b border-gray-100 w-48 overflow-x-hidden\">\n <div class=\"p-1 ml-2 font-bold\">Models</div>\n <button\n @click=\"hideSidebar = true\"\n class=\"ml-auto mr-2 p-2 rounded hover:bg-gray-200 focus:outline-none\"\n aria-label=\"Close sidebar\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"currentColor\"><path d=\"M660-320v-320L500-480l160 160ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm120-80v-560H200v560h120Zm80 0h360v-560H400v560Zm-80 0H200h120Z\"/></svg>\n </button>\n </div>\n <nav class=\"flex flex-1 flex-col\">\n <ul role=\"list\" class=\"flex flex-1 flex-col gap-y-7 p-1\">\n <li>\n <ul role=\"list\">\n <li v-for=\"model in models\">\n <router-link\n :to=\"'/model/' + model\"\n class=\"flex items-center gap-2 rounded-md py-2 pr-2 pl-2 text-sm text-gray-700\"\n :class=\"model === currentModel ? 'bg-ultramarine-100 font-bold text-gray-900' : 'hover:bg-ultramarine-50'\">\n <span class=\"truncate\">{{model}}</span>\n <span\n v-if=\"modelDocumentCounts && modelDocumentCounts[model] !== undefined && model !== currentModel\"\n class=\"ml-auto text-xs text-gray-500 bg-gray-100 rounded-md px-1 py-[2px]\"\n >\n {{formatCompactCount(modelDocumentCounts[model])}}\n </span>\n </router-link>\n </li>\n </ul>\n </li>\n </ul>\n <div v-if=\"models.length === 0 && status === 'loaded'\" class=\"p-2 bg-red-100\">\n No models found\n </div>\n </nav>\n </aside>\n <div class=\"documents bg-slate-50\" ref=\"documentsList\">\n <div class=\"relative h-[42px]\" style=\"z-index: 1000\">\n <div class=\"documents-menu bg-slate-50\">\n <div class=\"flex flex-row items-center w-full gap-2\">\n <document-search\n ref=\"documentSearch\"\n :value=\"searchText\"\n :schema-paths=\"schemaPaths\"\n @search=\"search\"\n >\n </document-search>\n <div>\n <span v-if=\"numDocuments == null\">Loading ...</span>\n <span v-else-if=\"typeof numDocuments === 'number'\">{{documents.length}}/{{numDocuments === 1 ? numDocuments + ' document' : numDocuments + ' documents'}}</span>\n </div>\n <button\n @click=\"stagingSelect\"\n type=\"button\"\n :class=\"{ 'bg-gray-500 ring-inset ring-2 ring-gray-300 hover:bg-gray-600': selectMultiple, 'bg-ultramarine-600 hover:bg-ultramarine-500' : !selectMultiple }\"\n class=\"rounded px-2 py-2 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\"\n >\n {{ selectMultiple ? 'Cancel' : 'Select' }}\n </button>\n <button\n v-show=\"selectMultiple\"\n @click=\"shouldShowUpdateMultipleModal=true;\"\n type=\"button\"\n class=\"rounded bg-green-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\"\n >\n Update\n </button>\n <button\n @click=\"shouldShowDeleteMultipleModal=true;\"\n type=\"button\"\n v-show=\"selectMultiple\"\n class=\"rounded bg-red-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500\"\n >\n Delete\n </button>\n <div class=\"relative\" v-show=\"!selectMultiple\" ref=\"actionsMenuContainer\" @keyup.esc.prevent=\"closeActionsMenu\">\n <button\n @click=\"toggleActionsMenu\"\n type=\"button\"\n aria-label=\"More actions\"\n class=\"rounded bg-white px-2 py-2 text-sm font-semibold text-gray-700 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-5 h-5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 6.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Zm0 6a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Zm0 6a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Z\" />\n </svg>\n </button>\n <div\n v-if=\"showActionsMenu\"\n class=\"absolute right-0 mt-2 w-48 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none z-20\"\n >\n <div class=\"py-1\">\n <button\n @click=\"shouldShowExportModal = true; showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Export\n </button>\n <button\n @click=\"shouldShowCreateModal = true; showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Create\n </button>\n <button\n @click=\"openFieldSelection(); showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Projection\n </button>\n <button\n @click=\"openIndexModal\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Indexes\n </button>\n <button\n @click=\"openCollectionInfo\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Collection Info\n </button>\n <button\n @click=\"findOldestDocument\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100\"\n >\n Find oldest document\n </button>\n </div>\n </div>\n </div>\n <span class=\"isolate inline-flex rounded-md shadow-sm\">\n <button\n @click=\"setOutputType('table')\"\n type=\"button\"\n class=\"relative inline-flex items-center rounded-none rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10\"\n :class=\"outputType === 'table' ? 'bg-gray-200' : 'bg-white'\">\n <img class=\"h-5 w-5\" src=\"images/table.svg\">\n </button>\n <button\n @click=\"setOutputType('json')\"\n type=\"button\"\n class=\"relative -ml-px inline-flex items-center 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 <button\n @click=\"setOutputType('map')\"\n :disabled=\"geoJsonFields.length === 0\"\n type=\"button\"\n :title=\"geoJsonFields.length > 0 ? 'Map view' : 'No GeoJSON fields detected'\"\n class=\"relative -ml-px inline-flex items-center rounded-none rounded-r-md px-2 py-2 ring-1 ring-inset ring-gray-300 focus:z-10\"\n :class=\"[\n geoJsonFields.length === 0 ? 'text-gray-300 cursor-not-allowed bg-gray-100' : 'text-gray-400 hover:bg-gray-50',\n outputType === 'map' ? 'bg-gray-200' : (geoJsonFields.length > 0 ? 'bg-white' : '')\n ]\">\n <svg class=\"h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 6.75V15m6-6v8.25m.503 3.498 4.875-2.437c.381-.19.622-.58.622-1.006V4.82c0-.836-.88-1.38-1.628-1.006l-3.869 1.934c-.317.159-.69.159-1.006 0L9.503 3.252a1.125 1.125 0 0 0-1.006 0L3.622 5.689C3.24 5.88 3 6.27 3 6.695V19.18c0 .836.88 1.38 1.628 1.006l3.869-1.934c.317-.159.69-.159 1.006 0l4.994 2.497c.317.158.69.158 1.006 0Z\" />\n </svg>\n </button>\n </span>\n </div>\n </div>\n </div>\n <div class=\"documents-container relative\">\n <div v-if=\"error\">\n <div class=\"bg-red-100 border border-red-400 text-red-700 px-4 py-3 relative m-4 rounded-md\" role=\"alert\">\n <span class=\"block font-bold\">Error</span>\n <span class=\"block\">{{ error }}</span>\n </div>\n </div>\n <table v-else-if=\"outputType === 'table'\">\n <thead class=\"bg-slate-50\">\n <th v-for=\"path in filteredPaths\" @click=\"addPathFilter(path.path)\" class=\"cursor-pointer p-3\">\n {{path.path}}\n <span class=\"path-type\">\n ({{(path.instance || 'unknown')}})\n </span>\n <span class=\"sort-arrow\" @click=\"sortDocs(1, path.path)\">{{sortBy[path.path] == 1 ? 'X' : '↑'}}</span>\n <span class=\"sort-arrow\" @click=\"sortDocs(-1, path.path)\">{{sortBy[path.path] == -1 ? 'X' : '↓'}}</span>\n </th>\n </thead>\n <tbody>\n <tr v-for=\"document in documents\" @click=\"handleDocumentClick(document, $event)\" :key=\"document._id\" class=\"bg-white hover:bg-slate-50\">\n <td v-for=\"schemaPath in filteredPaths\" class=\"p-3 cursor-pointer\" :class=\"{ 'bg-blue-200': selectedDocuments.some(x => x._id.toString() === document._id.toString()) }\">\n <component\n :is=\"getComponentForPath(schemaPath)\"\n :value=\"getValueForPath(document, schemaPath.path)\"\n :allude=\"getReferenceModel(schemaPath)\">\n </component>\n </td>\n </tr>\n </tbody>\n </table>\n <div v-else-if=\"outputType === 'json'\" class=\"flex flex-col space-y-2 p-1 mt-1\">\n <div\n v-for=\"document in documents\"\n :key=\"document._id\"\n @click=\"handleDocumentContainerClick(document, $event)\"\n :class=\"[\n 'group relative transition-colors rounded-md border border-slate-100',\n selectedDocuments.some(x => x._id.toString() === document._id.toString()) ? 'bg-blue-200' : 'hover:shadow-sm hover:border-slate-300 bg-white'\n ]\"\n >\n <button\n type=\"button\"\n class=\"absolute top-2 right-2 z-10 inline-flex items-center rounded bg-ultramarine-600 px-2 py-1 text-xs font-semibold text-white shadow-sm transition-opacity duration-150 opacity-0 group-hover:opacity-100 focus-visible:opacity-100 hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\"\n @click.stop=\"openDocument(document)\"\n >\n Open this Document\n </button>\n <list-json :value=\"filterDocument(document)\" :references=\"referenceMap\">\n </list-json>\n </div>\n </div>\n <div v-else-if=\"outputType === 'map'\" class=\"flex flex-col h-full\">\n <div class=\"p-2 bg-white border-b flex items-center gap-2\">\n <label class=\"text-sm font-medium text-gray-700\">GeoJSON Field:</label>\n <select\n :value=\"selectedGeoField\"\n @change=\"setSelectedGeoField($event.target.value)\"\n class=\"rounded-md border border-gray-300 py-1 px-2 text-sm focus:border-ultramarine-500 focus:ring-ultramarine-500\"\n >\n <option v-for=\"field in geoJsonFields\" :key=\"field.path\" :value=\"field.path\">\n {{ field.label }}\n </option>\n </select>\n <async-button\n @click=\"loadMoreDocuments\"\n :disabled=\"loadedAllDocs\"\n type=\"button\"\n class=\"rounded px-2 py-1 text-xs font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\"\n :class=\"loadedAllDocs ? 'bg-gray-400 cursor-not-allowed' : 'bg-ultramarine-600 hover:bg-ultramarine-500'\"\n >\n Load more\n </async-button>\n </div>\n <div class=\"flex-1 min-h-[400px]\" ref=\"modelsMap\"></div>\n </div>\n <div v-if=\"status === 'loading'\" class=\"loader\">\n <img src=\"images/loader.gif\">\n </div>\n </div>\n </div>\n <modal v-if=\"shouldShowExportModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowExportModal = false\">×</div>\n <export-query-results\n :schemaPaths=\"schemaPaths\"\n :search-text=\"searchText\"\n :currentModel=\"currentModel\"\n @done=\"shouldShowExportModal = false\">\n </export-query-results>\n </template>\n </modal>\n <modal v-if=\"shouldShowIndexModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowIndexModal = false\">×</div>\n <div class=\"text-xl font-bold mb-2\">Indexes</div>\n <div v-for=\"index in mongoDBIndexes\" class=\"w-full flex items-center\">\n <div class=\"grow shrink text-left flex justify-between items-center\" v-if=\"index.name != '_id_'\">\n <div>\n <div class=\"font-bold flex items-center gap-2\">\n <div>{{ index.name }}</div>\n <div v-if=\"isTTLIndex(index)\" class=\"rounded-full bg-ultramarine-100 px-2 py-0.5 text-xs font-semibold text-ultramarine-700\">\n TTL: {{ formatTTL(index.expireAfterSeconds) }}\n </div>\n </div>\n <div class=\"text-sm font-mono\">{{ JSON.stringify(index.key) }}</div>\n </div>\n <div>\n <async-button\n type=\"button\"\n @click=\"dropIndex(index.name)\"\n class=\"rounded-md bg-valencia-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-valencia-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600 disabled:bg-gray-400 disabled:cursor-not-allowed\">\n Drop\n </async-button>\n </div>\n </div>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowCollectionInfoModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowCollectionInfoModal = false\">×</div>\n <div class=\"text-xl font-bold mb-2\">Collection Info</div>\n <div v-if=\"!collectionInfo\" class=\"text-gray-600\">Loading collection details...</div>\n <div v-else class=\"space-y-3\">\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Documents</div>\n <div class=\"text-gray-900\">{{ formatNumber(collectionInfo.documentCount) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Indexes</div>\n <div class=\"text-gray-900\">{{ formatNumber(collectionInfo.indexCount) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Total Index Size</div>\n <div class=\"text-gray-900\">{{ formatCollectionSize(collectionInfo.totalIndexSize) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Total Storage Size</div>\n <div class=\"text-gray-900\">{{ formatCollectionSize(collectionInfo.size) }}</div>\n </div>\n <div class=\"flex flex-col gap-1\">\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Collation</div>\n <div class=\"text-gray-900\">{{ collectionInfo.hasCollation ? 'Yes' : 'No' }}</div>\n </div>\n <div v-if=\"collectionInfo.hasCollation\" class=\"rounded bg-gray-100 p-3 text-sm text-gray-800 overflow-x-auto\">\n <pre class=\"whitespace-pre-wrap\">{{ JSON.stringify(collectionInfo.collation, null, 2) }}</pre>\n </div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-gray-700\">Capped</div>\n <div class=\"text-gray-900\">{{ collectionInfo.capped ? 'Yes' : 'No' }}</div>\n </div>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowFieldModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowFieldModal = false; selectedPaths = [...filteredPaths];\">×</div>\n <div v-for=\"(path, index) in schemaPaths\" :key=\"index\" class=\"w-5 flex items-center\">\n <input class=\"mt-0 h-4 w-4 rounded border-gray-300 text-sky-600 focus:ring-sky-600 accent-sky-600\" type=\"checkbox\" :id=\"'path.path'+index\" @change=\"addOrRemove(path)\" :value=\"path.path\" :checked=\"isSelected(path.path)\" />\n <div class=\"ml-2 text-gray-700 grow shrink text-left\">\n <label :for=\"'path.path' + index\">{{path.path}}</label>\n </div>\n </div>\n <div class=\"mt-4 flex gap-2\">\n <button type=\"button\" @click=\"filterDocuments()\" class=\"rounded-md bg-ultramarine-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600\">Filter Selection</button>\n <button type=\"button\" @click=\"selectAll()\" class=\"rounded-md bg-forest-green-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\">Select All</button>\n <button type=\"button\" @click=\"deselectAll()\" class=\"rounded-md bg-valencia-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-valencia-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600\">Deselect All</button>\n <button type=\"button\" @click=\"resetDocuments()\" class=\"rounded-md bg-gray-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\" >Cancel</button>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowCreateModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowCreateModal = false;\">×</div>\n <create-document :currentModel=\"currentModel\" :paths=\"schemaPaths\" @close=\"closeCreationModal\"></create-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowUpdateMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowUpdateMultipleModal = false;\">×</div>\n <update-document :currentModel=\"currentModel\" :document=\"selectedDocuments\" :multiple=\"true\" @update=\"updateDocuments\" @close=\"shouldShowUpdateMultipleModal=false;\"></update-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowDeleteMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowDeleteMultipleModal = false;\">×</div>\n <h2>Are you sure you want to delete {{selectedDocuments.length}} documents?</h2>\n <div>\n <list-json :value=\"selectedDocuments\"></list-json>\n </div>\n <div class=\"flex gap-4\">\n <async-button @click=\"deleteDocuments\" class=\"rounded bg-red-500 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600\">\n Confirm\n </async-button>\n <button @click=\"shouldShowDeleteMultipleModal = false;\" class=\"rounded bg-gray-400 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500\">\n Cancel\n </button>\n </div>\n </template>\n </modal>\n</div>\n";
|
|
25526
26019
|
|
|
25527
26020
|
/***/ },
|
|
25528
26021
|
|
|
@@ -25559,6 +26052,28 @@ module.exports = "<div class=\"w-full h-full flex items-center justify-center\">
|
|
|
25559
26052
|
|
|
25560
26053
|
/***/ },
|
|
25561
26054
|
|
|
26055
|
+
/***/ "./frontend/src/task-by-name/task-by-name.html"
|
|
26056
|
+
/*!*****************************************************!*\
|
|
26057
|
+
!*** ./frontend/src/task-by-name/task-by-name.html ***!
|
|
26058
|
+
\*****************************************************/
|
|
26059
|
+
(module) {
|
|
26060
|
+
|
|
26061
|
+
"use strict";
|
|
26062
|
+
module.exports = "<div class=\"p-4 space-y-6\">\n <div v-if=\"status === 'init'\">\n <img src=\"images/loader.gif\" alt=\"Loading\" />\n </div>\n <div v-else-if=\"status === 'error'\" class=\"text-red-600\">\n {{ errorMessage }}\n </div>\n <task-details\n v-else-if=\"taskGroup\"\n :task-group=\"taskGroup\"\n :back-to=\"{ name: 'tasks' }\"\n @task-created=\"onTaskCreated\"\n @task-cancelled=\"onTaskCancelled\"\n ></task-details>\n</div>\n";
|
|
26063
|
+
|
|
26064
|
+
/***/ },
|
|
26065
|
+
|
|
26066
|
+
/***/ "./frontend/src/task-single/task-single.html"
|
|
26067
|
+
/*!***************************************************!*\
|
|
26068
|
+
!*** ./frontend/src/task-single/task-single.html ***!
|
|
26069
|
+
\***************************************************/
|
|
26070
|
+
(module) {
|
|
26071
|
+
|
|
26072
|
+
"use strict";
|
|
26073
|
+
module.exports = "<div class=\"p-4 space-y-6\">\n <div v-if=\"status === 'init'\">\n <img src=\"images/loader.gif\" alt=\"Loading\" />\n </div>\n <div v-else-if=\"status === 'error'\" class=\"text-red-600\">\n {{ errorMessage }}\n </div>\n <div v-else-if=\"status === 'notfound'\" class=\"text-gray-600\">\n Task not found.\n </div>\n <div v-else-if=\"task\" class=\"max-w-4xl\">\n <button @click=\"goBack\" class=\"text-gray-500 hover:text-gray-700 mb-4 flex items-center gap-1\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\"></path>\n </svg>\n Back to {{ task.name }}\n </button>\n <h1 class=\"text-2xl font-bold text-gray-700 mb-1\">{{ task.name }}</h1>\n <p class=\"text-gray-500 mb-6\">Task details</p>\n\n <div class=\"bg-white rounded-lg shadow p-6 md:p-8\">\n <div class=\"flex items-center gap-3 mb-6\">\n <span class=\"text-sm font-medium text-gray-900\">ID: {{ task.id }}</span>\n <span\n class=\"text-xs px-2 py-1 rounded-full font-medium\"\n :class=\"getStatusColor(task.status)\"\n >\n {{ task?.status }}\n </span>\n </div>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-6\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Scheduled At</label>\n <div class=\"text-sm text-gray-900\">{{ formatDate(task.scheduledAt) }}</div>\n </div>\n <div v-if=\"task?.startedAt\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Started At</label>\n <div class=\"text-sm text-gray-900\">{{ formatDate(task.startedAt) }}</div>\n </div>\n <div v-if=\"task?.completedAt\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Completed At</label>\n <div class=\"text-sm text-gray-900\">{{ formatDate(task.completedAt) }}</div>\n </div>\n </div>\n\n <div v-if=\"task?.params\" class=\"mb-6\">\n <label class=\"block text-sm font-medium text-gray-700 mb-2\">Params</label>\n <div class=\"bg-gray-50 rounded-md p-4\">\n <list-json :value=\"task.params\"></list-json>\n </div>\n </div>\n\n <div v-if=\"task?.result\" class=\"mb-6\">\n <label class=\"block text-sm font-medium text-gray-700 mb-2\">Result</label>\n <div class=\"bg-gray-50 rounded-md p-4\">\n <list-json :value=\"task.result\"></list-json>\n </div>\n </div>\n\n <div v-if=\"task?.error\" class=\"mb-6\">\n <label class=\"block text-sm font-medium text-gray-700 mb-2\">Error</label>\n <div class=\"bg-gray-50 rounded-md p-4\">\n <list-json :value=\"task.error\"></list-json>\n </div>\n </div>\n\n <div class=\"flex flex-wrap gap-3 pt-4 border-t border-gray-200\">\n <button\n @click=\"showRescheduleConfirmation(task)\"\n class=\"flex items-center justify-center gap-2 bg-gradient-to-r from-blue-500 to-blue-600 text-white px-4 py-2 rounded-lg text-sm font-medium hover:from-blue-600 hover:to-blue-700 disabled:opacity-50 disabled:cursor-not-allowed\"\n :disabled=\"task.status === 'in_progress'\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"></path>\n </svg>\n Reschedule\n </button>\n <button\n @click=\"showRunConfirmation(task)\"\n class=\"flex items-center justify-center gap-2 bg-gradient-to-r from-green-500 to-green-600 text-white px-4 py-2 rounded-lg text-sm font-medium hover:from-green-600 hover:to-green-700 disabled:opacity-50 disabled:cursor-not-allowed\"\n :disabled=\"task.status === 'in_progress'\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 3l14 9-14 9V3z\"></path>\n </svg>\n Run Now\n </button>\n <button\n v-if=\"task.status === 'pending'\"\n @click=\"showCancelConfirmation(task)\"\n class=\"flex items-center justify-center gap-2 bg-gradient-to-r from-red-500 to-red-600 text-white px-4 py-2 rounded-lg text-sm font-medium hover:from-red-600 hover:to-red-700\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path>\n </svg>\n Cancel Task\n </button>\n </div>\n </div>\n </div>\n\n <!-- Reschedule Modal -->\n <modal v-if=\"showRescheduleModal\" containerClass=\"!max-w-md\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showRescheduleModal = false\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"p-6\">\n <h3 class=\"text-lg font-medium text-gray-900 mb-4\">Reschedule Task</h3>\n <p class=\"text-sm text-gray-600 mb-2\">Reschedule task <strong>{{ selectedTask?.id }}</strong>?</p>\n <p class=\"text-sm text-gray-500 mb-4\">This will reset the task's status and schedule it to run again.</p>\n <label for=\"newScheduledTime\" class=\"block text-sm font-medium text-gray-700 mb-2\">New Scheduled Time</label>\n <input\n id=\"newScheduledTime\"\n v-model=\"newScheduledTime\"\n type=\"datetime-local\"\n class=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 mb-4\"\n />\n <div class=\"flex gap-3\">\n <button @click=\"confirmRescheduleTask\" class=\"flex-1 bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 font-medium\">Reschedule</button>\n <button @click=\"showRescheduleModal = false\" class=\"flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400 font-medium\">Cancel</button>\n </div>\n </div>\n </template>\n </modal>\n\n <!-- Run Modal -->\n <modal v-if=\"showRunModal\" containerClass=\"!max-w-md\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showRunModal = false\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"p-6\">\n <h3 class=\"text-lg font-medium text-gray-900 mb-4\">Run Task Now</h3>\n <p class=\"text-sm text-gray-600 mb-2\">Run task <strong>{{ selectedTask?.id }}</strong> immediately?</p>\n <p class=\"text-sm text-gray-500 mb-4\">This will execute the task right away, bypassing its scheduled time.</p>\n <div class=\"flex gap-3\">\n <button @click=\"confirmRunTask\" class=\"flex-1 bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 font-medium\">Run Now</button>\n <button @click=\"showRunModal = false\" class=\"flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400 font-medium\">Cancel</button>\n </div>\n </div>\n </template>\n </modal>\n\n <!-- Cancel Task Modal -->\n <modal v-if=\"showCancelModal\" containerClass=\"!max-w-md\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showCancelModal = false\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"p-6\">\n <h3 class=\"text-lg font-medium text-gray-900 mb-4\">Cancel Task</h3>\n <p class=\"text-sm text-gray-600 mb-2\">Cancel task <strong>{{ selectedTask?.id }}</strong>?</p>\n <p class=\"text-sm text-gray-500 mb-4\">This will permanently cancel the task and it cannot be undone.</p>\n <div class=\"flex gap-3\">\n <button @click=\"confirmCancelTask\" class=\"flex-1 bg-red-600 text-white px-4 py-2 rounded-md hover:bg-red-700 font-medium\">Cancel Task</button>\n <button @click=\"showCancelModal = false\" class=\"flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400 font-medium\">Keep Task</button>\n </div>\n </div>\n </template>\n </modal>\n</div>\n";
|
|
26074
|
+
|
|
26075
|
+
/***/ },
|
|
26076
|
+
|
|
25562
26077
|
/***/ "./frontend/src/tasks/task-details/task-details.html"
|
|
25563
26078
|
/*!***********************************************************!*\
|
|
25564
26079
|
!*** ./frontend/src/tasks/task-details/task-details.html ***!
|
|
@@ -25566,7 +26081,7 @@ module.exports = "<div class=\"w-full h-full flex items-center justify-center\">
|
|
|
25566
26081
|
(module) {
|
|
25567
26082
|
|
|
25568
26083
|
"use strict";
|
|
25569
|
-
module.exports = "<div class=\"p-4 space-y-6\">\n <div class=\"flex items-center justify-between\">\n <div>\n <button @click=\"$emit('back')\" class=\"text-gray-500 hover:text-gray-700 mb-2\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\"></path>\n </svg>\n Back to Task Groups\n </button>\n <h1 class=\"text-2xl font-bold text-gray-700\">{{ taskGroup.name }}</h1>\n <p class=\"text-gray-500\">Total: {{ taskGroup.totalCount }} tasks</p>\n </div>\n\n </div>\n\n <!-- Status Summary -->\n <div class=\"grid grid-cols-2 sm:grid-cols-4 gap-4\">\n <button \n @click=\"filterByStatus('pending')\"\n class=\"bg-yellow-50 border border-yellow-200 rounded-md p-3 text-center hover:bg-yellow-100 transition-colors cursor-pointer\"\n :class=\"{ 'ring-2 ring-yellow-400': currentFilter === 'pending' }\"\n >\n <div class=\"text-xs text-yellow-600 font-medium\">Pending</div>\n <div class=\"text-lg font-bold text-yellow-700\">{{ taskGroup.statusCounts.pending || 0 }}</div>\n </button>\n <button \n @click=\"filterByStatus('succeeded')\"\n class=\"bg-green-50 border border-green-200 rounded-md p-3 text-center hover:bg-green-100 transition-colors cursor-pointer\"\n :class=\"{ 'ring-2 ring-green-400': currentFilter === 'succeeded' }\"\n >\n <div class=\"text-xs text-green-600 font-medium\">Succeeded</div>\n <div class=\"text-lg font-bold text-green-700\">{{ taskGroup.statusCounts.succeeded || 0 }}</div>\n </button>\n <button \n @click=\"filterByStatus('failed')\"\n class=\"bg-red-50 border border-red-200 rounded-md p-3 text-center hover:bg-red-100 transition-colors cursor-pointer\"\n :class=\"{ 'ring-2 ring-red-400': currentFilter === 'failed' }\"\n >\n <div class=\"text-xs text-red-600 font-medium\">Failed</div>\n <div class=\"text-lg font-bold text-red-700\">{{ taskGroup.statusCounts.failed || 0 }}</div>\n </button>\n <button \n @click=\"filterByStatus('cancelled')\"\n class=\"bg-gray-50 border border-gray-200 rounded-md p-3 text-center hover:bg-gray-100 transition-colors cursor-pointer\"\n :class=\"{ 'ring-2 ring-gray-400': currentFilter === 'cancelled' }\"\n >\n <div class=\"text-xs text-gray-600 font-medium\">Cancelled</div>\n <div class=\"text-lg font-bold text-gray-700\">{{ taskGroup.statusCounts.cancelled || 0 }}</div>\n </button>\n </div>\n\n <!-- Task List -->\n <div class=\"bg-white rounded-lg shadow\">\n <div class=\"px-6 py-4 border-b border-gray-200 flex items-center justify-between\">\n <h2 class=\"text-lg font-semibold text-gray-700\">\n Individual Tasks\n <span v-if=\"currentFilter\" class=\"text-sm font-normal text-gray-500 ml-2\">\n (Filtered by {{ currentFilter }})\n </span>\n </h2>\n <button \n v-if=\"currentFilter\"\n @click=\"clearFilter\"\n class=\"text-sm text-ultramarine-600 hover:text-ultramarine-700 font-medium\"\n >\n Show All\n </button>\n </div>\n <div class=\"divide-y divide-gray-200\">\n <div v-for=\"task in sortedTasks\" :key=\"task.id\" class=\"p-6\">\n <div class=\"flex items-start justify-between\">\n <div class=\"flex-1\">\n <div class=\"flex items-center gap-3 mb-2\">\n <span class=\"text-sm font-medium text-gray-900\">Task ID: {{ task.id }}</span>\n <span\n class=\"text-xs px-2 py-1 rounded-full font-medium\"\n :class=\"getStatusColor(task.status)\"\n >\n {{ task.status }}\n </span>\n </div>\n \n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mb-4\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Scheduled At</label>\n <div class=\"text-sm text-gray-900\">{{ formatDate(task.scheduledAt) }}</div>\n </div>\n <div v-if=\"task.startedAt\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Started At</label>\n <div class=\"text-sm text-gray-900\">{{ formatDate(task.startedAt) }}</div>\n </div>\n <div v-if=\"task.completedAt\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Completed At</label>\n <div class=\"text-sm text-gray-900\">{{ formatDate(task.completedAt) }}</div>\n </div>\n <div v-if=\"task.error\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Error</label>\n <div class=\"text-sm text-red-600\">{{ task.error }}</div>\n </div>\n </div>\n\n <!-- Task Parameters -->\n <div v-if=\"task.parameters && Object.keys(task.parameters).length > 0\">\n <label class=\"block text-sm font-medium text-gray-700 mb-2\">Parameters</label>\n <div class=\"bg-gray-50 rounded-md p-3\">\n <pre class=\"text-sm text-gray-800 whitespace-pre-wrap\">{{ JSON.stringify(task.parameters, null, 2) }}</pre>\n </div>\n </div>\n </div>\n \n <div class=\"flex flex-col gap-3 ml-6\">\n <button \n @click=\"showRescheduleConfirmation(task)\"\n class=\"flex items-center justify-center gap-2 bg-gradient-to-r from-blue-500 to-blue-600 text-white px-4 py-2 rounded-lg text-sm font-medium hover:from-blue-600 hover:to-blue-700 transform hover:scale-105 transition-all duration-200 shadow-md hover:shadow-lg disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none\"\n :disabled=\"task.status === 'in_progress'\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"></path>\n </svg>\n Reschedule\n </button>\n <button \n @click=\"showRunConfirmation(task)\"\n class=\"flex items-center justify-center gap-2 bg-gradient-to-r from-green-500 to-green-600 text-white px-4 py-2 rounded-lg text-sm font-medium hover:from-green-600 hover:to-green-700 transform hover:scale-105 transition-all duration-200 shadow-md hover:shadow-lg disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none\"\n :disabled=\"task.status === 'in_progress'\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 3l14 9-14 9V3z\"></path>\n </svg>\n Run Now\n </button>\n <button \n v-if=\"task.status === 'pending'\"\n @click=\"showCancelConfirmation(task)\"\n class=\"flex items-center justify-center gap-2 bg-gradient-to-r from-red-500 to-red-600 text-white px-4 py-2 rounded-lg text-sm font-medium hover:from-red-600 hover:to-red-700 transform hover:scale-105 transition-all duration-200 shadow-md hover:shadow-lg\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path>\n </svg>\n Cancel\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Reschedule Confirmation Modal -->\n <modal v-if=\"showRescheduleModal\" containerClass=\"!max-w-md\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showRescheduleModal = false;\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"p-6\">\n <div class=\"flex items-center mb-4\">\n <div class=\"flex-shrink-0\">\n <svg class=\"w-6 h-6 text-blue-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"></path>\n </svg>\n </div>\n <div class=\"ml-3\">\n <h3 class=\"text-lg font-medium text-gray-900\">Reschedule Task</h3>\n </div>\n </div>\n <div class=\"mb-4\">\n <p class=\"text-sm text-gray-600\">\n Are you sure you want to reschedule task <strong>{{ selectedTask?.id }}</strong>?\n </p>\n <p class=\"text-sm text-gray-500 mt-2\">\n This will reset the task's status and schedule it to run again.\n </p>\n \n <div class=\"mt-4\">\n <label for=\"newScheduledTime\" class=\"block text-sm font-medium text-gray-700 mb-2\">\n New Scheduled Time\n </label>\n <input\n id=\"newScheduledTime\"\n v-model=\"newScheduledTime\"\n type=\"datetime-local\"\n class=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500\"\n required\n />\n </div>\n </div>\n <div class=\"flex gap-3\">\n <button \n @click=\"confirmRescheduleTask\"\n class=\"flex-1 bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 font-medium\"\n >\n Reschedule\n </button>\n <button \n @click=\"showRescheduleModal = false\"\n class=\"flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400 font-medium\"\n >\n Cancel\n </button>\n </div>\n </div>\n </template>\n </modal>\n\n <!-- Run Task Confirmation Modal -->\n <modal v-if=\"showRunModal\" containerClass=\"!max-w-md\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showRunModal = false;\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"p-6\">\n <div class=\"flex items-center mb-4\">\n <div class=\"flex-shrink-0\">\n <svg class=\"w-6 h-6 text-green-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M14.828 14.828a4 4 0 01-5.656 0M9 10h1m4 0h1m-6 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"></path>\n </svg>\n </div>\n <div class=\"ml-3\">\n <h3 class=\"text-lg font-medium text-gray-900\">Run Task Now</h3>\n </div>\n </div>\n <div class=\"mb-4\">\n <p class=\"text-sm text-gray-600\">\n Are you sure you want to run task <strong>{{ selectedTask?.id }}</strong> immediately?\n </p>\n <p class=\"text-sm text-gray-500 mt-2\">\n This will execute the task right away, bypassing its scheduled time.\n </p>\n </div>\n <div class=\"flex gap-3\">\n <button \n @click=\"confirmRunTask\"\n class=\"flex-1 bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 font-medium\"\n >\n Run Now\n </button>\n <button \n @click=\"showRunModal = false\"\n class=\"flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400 font-medium\"\n >\n Cancel\n </button>\n </div>\n </div>\n </template>\n </modal>\n\n <!-- Cancel Task Confirmation Modal -->\n <modal v-if=\"showCancelModal\" containerClass=\"!max-w-md\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showCancelModal = false;\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"p-6\">\n <div class=\"flex items-center mb-4\">\n <div class=\"flex-shrink-0\">\n <svg class=\"w-6 h-6 text-red-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path>\n </svg>\n </div>\n <div class=\"ml-3\">\n <h3 class=\"text-lg font-medium text-gray-900\">Cancel Task</h3>\n </div>\n </div>\n <div class=\"mb-4\">\n <p class=\"text-sm text-gray-600\">\n Are you sure you want to cancel task <strong>{{ selectedTask?.id }}</strong>?\n </p>\n <p class=\"text-sm text-gray-500 mt-2\">\n This will permanently cancel the task and it cannot be undone.\n </p>\n </div>\n <div class=\"flex gap-3\">\n <button \n @click=\"confirmCancelTask\"\n class=\"flex-1 bg-red-600 text-white px-4 py-2 rounded-md hover:bg-red-700 font-medium\"\n >\n Cancel Task\n </button>\n <button \n @click=\"showCancelModal = false\"\n class=\"flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400 font-medium\"\n >\n Keep Task\n </button>\n </div>\n </div>\n </template>\n </modal>\n</div>\n\n";
|
|
26084
|
+
module.exports = "<div class=\"p-4 space-y-6\">\n <div class=\"flex items-center justify-between\">\n <div>\n <button @click=\"goBack\" class=\"text-gray-500 hover:text-gray-700 mb-2\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\"></path>\n </svg>\n {{ backLabel }}\n </button>\n <h1 class=\"text-2xl font-bold text-gray-700\">{{ taskGroup.name }}</h1>\n <p class=\"text-gray-500\">Total: {{ taskGroup.totalCount }} tasks</p>\n </div>\n\n </div>\n\n <!-- Status Summary -->\n <div class=\"space-y-3\">\n <div class=\"flex items-center justify-between\">\n <span class=\"text-sm font-medium text-gray-700\">Status</span>\n <div class=\"flex rounded-md shadow-sm\" role=\"group\">\n <button\n type=\"button\"\n @click=\"statusView = 'summary'\"\n class=\"px-3 py-1.5 text-sm font-medium rounded-l-md border transition-colors\"\n :class=\"statusView === 'summary' ? 'bg-ultramarine-600 text-white border-ultramarine-600' : 'bg-white text-gray-700 border-gray-300 hover:bg-gray-50'\"\n >\n Summary\n </button>\n <button\n type=\"button\"\n @click=\"statusView = 'chart'\"\n class=\"px-3 py-1.5 text-sm font-medium rounded-r-md border border-l-0 transition-colors\"\n :class=\"statusView === 'chart' ? 'bg-ultramarine-600 text-white border-ultramarine-600' : 'bg-white text-gray-700 border-gray-300 hover:bg-gray-50'\"\n >\n Chart\n </button>\n </div>\n </div>\n <!-- Summary view -->\n <div v-show=\"statusView === 'summary'\" class=\"grid grid-cols-2 sm:grid-cols-4 gap-4\">\n <button \n @click=\"filterByStatus('pending')\"\n class=\"bg-yellow-50 border border-yellow-200 rounded-md p-3 text-center hover:bg-yellow-100 transition-colors cursor-pointer\"\n :class=\"{ 'ring-2 ring-yellow-400': currentFilter === 'pending' }\"\n >\n <div class=\"text-xs text-yellow-600 font-medium\">Pending</div>\n <div class=\"text-lg font-bold text-yellow-700\">{{ taskGroup.statusCounts.pending || 0 }}</div>\n </button>\n <button \n @click=\"filterByStatus('succeeded')\"\n class=\"bg-green-50 border border-green-200 rounded-md p-3 text-center hover:bg-green-100 transition-colors cursor-pointer\"\n :class=\"{ 'ring-2 ring-green-400': currentFilter === 'succeeded' }\"\n >\n <div class=\"text-xs text-green-600 font-medium\">Succeeded</div>\n <div class=\"text-lg font-bold text-green-700\">{{ taskGroup.statusCounts.succeeded || 0 }}</div>\n </button>\n <button \n @click=\"filterByStatus('failed')\"\n class=\"bg-red-50 border border-red-200 rounded-md p-3 text-center hover:bg-red-100 transition-colors cursor-pointer\"\n :class=\"{ 'ring-2 ring-red-400': currentFilter === 'failed' }\"\n >\n <div class=\"text-xs text-red-600 font-medium\">Failed</div>\n <div class=\"text-lg font-bold text-red-700\">{{ taskGroup.statusCounts.failed || 0 }}</div>\n </button>\n <button \n @click=\"filterByStatus('cancelled')\"\n class=\"bg-gray-50 border border-gray-200 rounded-md p-3 text-center hover:bg-gray-100 transition-colors cursor-pointer\"\n :class=\"{ 'ring-2 ring-gray-400': currentFilter === 'cancelled' }\"\n >\n <div class=\"text-xs text-gray-600 font-medium\">Cancelled</div>\n <div class=\"text-lg font-bold text-gray-700\">{{ taskGroup.statusCounts.cancelled || 0 }}</div>\n </button>\n </div>\n <!-- Chart view -->\n <div v-show=\"statusView === 'chart'\" class=\"flex flex-col items-center justify-center bg-white border border-gray-200 rounded-lg p-4 gap-3\" style=\"min-height: 280px;\">\n <div v-if=\"taskGroup.totalCount > 0\" class=\"w-[240px] h-[240px] shrink-0\">\n <canvas ref=\"statusPieChart\" width=\"240\" height=\"240\" class=\"block\"></canvas>\n </div>\n <p v-else class=\"text-gray-500 text-sm py-8\">No tasks to display</p>\n <!-- Selection labels: show which segment is selected (click to filter) -->\n <div v-if=\"taskGroup.totalCount > 0\" class=\"flex flex-wrap justify-center gap-2\">\n <button\n v-for=\"status in statusOrderForDisplay\"\n :key=\"status\"\n type=\"button\"\n class=\"text-xs px-2 py-1 rounded-full font-medium transition-all cursor-pointer\"\n :class=\"currentFilter === status ? getStatusPillClass(status) : 'bg-gray-100 text-gray-500 hover:bg-gray-200'\"\n @click=\"filterByStatus(status)\"\n >\n {{ statusLabel(status) }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"bg-white rounded-lg shadow\">\n <div class=\"px-6 py-6 border-b border-gray-200 flex items-center justify-between bg-gray-50\">\n <h2 class=\"text-xl font-bold text-gray-900\">\n Individual Tasks\n <span v-if=\"currentFilter\" class=\"ml-3 text-base font-semibold text-ultramarine-700\">\n (Filtered by {{ currentFilter }})\n </span>\n </h2>\n <button \n v-if=\"currentFilter\"\n @click=\"clearFilter\"\n class=\"text-sm font-semibold text-ultramarine-600 hover:text-ultramarine-700\"\n >\n Show All\n </button>\n </div>\n <div class=\"divide-y divide-gray-200\">\n <div v-for=\"task in sortedTasks\" :key=\"task.id\" class=\"p-6\">\n <div class=\"flex items-start justify-between\">\n <div class=\"flex-1\">\n <div class=\"flex items-center gap-3 mb-2\">\n <span class=\"text-sm font-medium text-gray-900\">Task ID: {{ task.id }}</span>\n <router-link\n v-if=\"backTo\"\n :to=\"taskDetailRoute(task)\"\n class=\"text-sm text-ultramarine-600 hover:text-ultramarine-700 font-medium\"\n >\n View details\n </router-link>\n <span\n class=\"text-xs px-2 py-1 rounded-full font-medium\"\n :class=\"getStatusColor(task.status)\"\n >\n {{ task.status }}\n </span>\n </div>\n \n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mb-4\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Scheduled At</label>\n <div class=\"text-sm text-gray-900\">{{ formatDate(task.scheduledAt) }}</div>\n </div>\n <div v-if=\"task.startedAt\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Started At</label>\n <div class=\"text-sm text-gray-900\">{{ formatDate(task.startedAt) }}</div>\n </div>\n <div v-if=\"task.completedAt\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Completed At</label>\n <div class=\"text-sm text-gray-900\">{{ formatDate(task.completedAt) }}</div>\n </div>\n <div v-if=\"task.error\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Error</label>\n <div class=\"text-sm text-red-600\">{{ task.error }}</div>\n </div>\n </div>\n\n <!-- Task Parameters -->\n <div v-if=\"task.parameters && Object.keys(task.parameters).length > 0\">\n <label class=\"block text-sm font-medium text-gray-700 mb-2\">Parameters</label>\n <div class=\"bg-gray-50 rounded-md p-3\">\n <pre class=\"text-sm text-gray-800 whitespace-pre-wrap\">{{ JSON.stringify(task.parameters, null, 2) }}</pre>\n </div>\n </div>\n </div>\n \n <div class=\"flex flex-col gap-3 ml-6\">\n <button \n @click=\"showRescheduleConfirmation(task)\"\n class=\"flex items-center justify-center gap-2 bg-gradient-to-r from-blue-500 to-blue-600 text-white px-4 py-2 rounded-lg text-sm font-medium hover:from-blue-600 hover:to-blue-700 transform hover:scale-105 transition-all duration-200 shadow-md hover:shadow-lg disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none\"\n :disabled=\"task.status === 'in_progress'\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"></path>\n </svg>\n Reschedule\n </button>\n <button \n @click=\"showRunConfirmation(task)\"\n class=\"flex items-center justify-center gap-2 bg-gradient-to-r from-green-500 to-green-600 text-white px-4 py-2 rounded-lg text-sm font-medium hover:from-green-600 hover:to-green-700 transform hover:scale-105 transition-all duration-200 shadow-md hover:shadow-lg disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none\"\n :disabled=\"task.status === 'in_progress'\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 3l14 9-14 9V3z\"></path>\n </svg>\n Run Now\n </button>\n <button \n v-if=\"task.status === 'pending'\"\n @click=\"showCancelConfirmation(task)\"\n class=\"flex items-center justify-center gap-2 bg-gradient-to-r from-red-500 to-red-600 text-white px-4 py-2 rounded-lg text-sm font-medium hover:from-red-600 hover:to-red-700 transform hover:scale-105 transition-all duration-200 shadow-md hover:shadow-lg\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path>\n </svg>\n Cancel\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Reschedule Confirmation Modal -->\n <modal v-if=\"showRescheduleModal\" containerClass=\"!max-w-md\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showRescheduleModal = false;\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"p-6\">\n <div class=\"flex items-center mb-4\">\n <div class=\"flex-shrink-0\">\n <svg class=\"w-6 h-6 text-blue-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"></path>\n </svg>\n </div>\n <div class=\"ml-3\">\n <h3 class=\"text-lg font-medium text-gray-900\">Reschedule Task</h3>\n </div>\n </div>\n <div class=\"mb-4\">\n <p class=\"text-sm text-gray-600\">\n Are you sure you want to reschedule task <strong>{{ selectedTask?.id }}</strong>?\n </p>\n <p class=\"text-sm text-gray-500 mt-2\">\n This will reset the task's status and schedule it to run again.\n </p>\n \n <div class=\"mt-4\">\n <label for=\"newScheduledTime\" class=\"block text-sm font-medium text-gray-700 mb-2\">\n New Scheduled Time\n </label>\n <input\n id=\"newScheduledTime\"\n v-model=\"newScheduledTime\"\n type=\"datetime-local\"\n class=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500\"\n required\n />\n </div>\n </div>\n <div class=\"flex gap-3\">\n <button \n @click=\"confirmRescheduleTask\"\n class=\"flex-1 bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 font-medium\"\n >\n Reschedule\n </button>\n <button \n @click=\"showRescheduleModal = false\"\n class=\"flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400 font-medium\"\n >\n Cancel\n </button>\n </div>\n </div>\n </template>\n </modal>\n\n <!-- Run Task Confirmation Modal -->\n <modal v-if=\"showRunModal\" containerClass=\"!max-w-md\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showRunModal = false;\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"p-6\">\n <div class=\"flex items-center mb-4\">\n <div class=\"flex-shrink-0\">\n <svg class=\"w-6 h-6 text-green-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M14.828 14.828a4 4 0 01-5.656 0M9 10h1m4 0h1m-6 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"></path>\n </svg>\n </div>\n <div class=\"ml-3\">\n <h3 class=\"text-lg font-medium text-gray-900\">Run Task Now</h3>\n </div>\n </div>\n <div class=\"mb-4\">\n <p class=\"text-sm text-gray-600\">\n Are you sure you want to run task <strong>{{ selectedTask?.id }}</strong> immediately?\n </p>\n <p class=\"text-sm text-gray-500 mt-2\">\n This will execute the task right away, bypassing its scheduled time.\n </p>\n </div>\n <div class=\"flex gap-3\">\n <button \n @click=\"confirmRunTask\"\n class=\"flex-1 bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 font-medium\"\n >\n Run Now\n </button>\n <button \n @click=\"showRunModal = false\"\n class=\"flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400 font-medium\"\n >\n Cancel\n </button>\n </div>\n </div>\n </template>\n </modal>\n\n <!-- Cancel Task Confirmation Modal -->\n <modal v-if=\"showCancelModal\" containerClass=\"!max-w-md\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showCancelModal = false;\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"p-6\">\n <div class=\"flex items-center mb-4\">\n <div class=\"flex-shrink-0\">\n <svg class=\"w-6 h-6 text-red-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path>\n </svg>\n </div>\n <div class=\"ml-3\">\n <h3 class=\"text-lg font-medium text-gray-900\">Cancel Task</h3>\n </div>\n </div>\n <div class=\"mb-4\">\n <p class=\"text-sm text-gray-600\">\n Are you sure you want to cancel task <strong>{{ selectedTask?.id }}</strong>?\n </p>\n <p class=\"text-sm text-gray-500 mt-2\">\n This will permanently cancel the task and it cannot be undone.\n </p>\n </div>\n <div class=\"flex gap-3\">\n <button \n @click=\"confirmCancelTask\"\n class=\"flex-1 bg-red-600 text-white px-4 py-2 rounded-md hover:bg-red-700 font-medium\"\n >\n Cancel Task\n </button>\n <button \n @click=\"showCancelModal = false\"\n class=\"flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400 font-medium\"\n >\n Keep Task\n </button>\n </div>\n </div>\n </template>\n </modal>\n</div>\n\n";
|
|
25570
26085
|
|
|
25571
26086
|
/***/ },
|
|
25572
26087
|
|
|
@@ -25588,7 +26103,7 @@ module.exports = "";
|
|
|
25588
26103
|
(module) {
|
|
25589
26104
|
|
|
25590
26105
|
"use strict";
|
|
25591
|
-
module.exports = "<div class=\"p-4 space-y-6\">\n <!-- Task Details View -->\n <task-details \n v-if=\"showTaskDetails && selectedTaskGroup\"\n :task-group=\"selectedTaskGroup\"\n :current-filter=\"taskDetailsFilter\"\n @back=\"hideTaskDetails\"\n @task-created=\"onTaskCreated\"\n @task-cancelled=\"onTaskCancelled\"\n @update:current-filter=\"taskDetailsFilter = $event\"\n ></task-details>\n\n <!-- Main Tasks View -->\n <div v-else>\n <h1 class=\"text-2xl font-bold text-gray-700 mb-4\">Task Overview</h1>\n <div v-if=\"status == 'init'\">\n <img src=\"images/loader.gif\" />\n </div>\n <!-- Task List -->\n <div class=\"bg-white p-4 rounded-lg shadow\" v-if=\"status == 'loaded'\">\n <div class=\"mb-4\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Filter by Date:</label>\n <select v-model=\"selectedRange\" @change=\"updateDateRange\" class=\"border-gray-300 rounded-md shadow-sm w-full p-2\">\n <option v-for=\"option in dateFilters\" :key=\"option.value\" :value=\"option.value\">\n {{ option.label }}\n </option>\n </select>\n </div>\n <div class=\"mb-4\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Filter by Status:</label>\n <select v-model=\"selectedStatus\" @change=\"getTasks\" class=\"border-gray-300 rounded-md shadow-sm w-full p-2\">\n <option v-for=\"option in statusFilters\" :key=\"option.value\" :value=\"option.value\">\n {{ option.label }}\n </option>\n </select>\n </div>\n <div class=\"mb-4\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Search by Task Name:</label>\n <input \n v-model=\"searchQuery\" \n type=\"text\" \n @input=\"onSearchInput\"\n class=\"border-gray-300 rounded-md shadow-sm w-full p-2\"\n placeholder=\"Enter task name to search...\"\n >\n </div>\n <div class=\"mb-4\">\n <button\n @click=\"resetFilters\"\n class=\"w-full bg-gray-200 text-gray-700 hover:bg-gray-300 font-medium py-2 px-4 rounded-md transition\"\n >\n Reset Filters\n </button>\n </div>\n <div class=\"mb-6\">\n <button\n @click=\"openCreateTaskModal\"\n class=\"w-full bg-ultramarine-600 text-white hover:bg-ultramarine-700 font-medium py-2 px-4 rounded-md transition\"\n >\n Create New Task\n </button>\n </div>\n <!-- Summary Section -->\n <div class=\"grid grid-cols-2 sm:grid-cols-4 gap-4\">\n <button \n @click=\"setStatusFilter('pending')\"\n :class=\"getStatusColor('pending') + ' p-4 rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-200 cursor-pointer border-2 border-yellow-200 hover:border-yellow-300'\"\n >\n <div class=\"text-sm\">Scheduled</div>\n <div class=\"text-2xl font-bold\">{{pendingCount}}</div>\n </button>\n <button \n @click=\"setStatusFilter('succeeded')\"\n :class=\"getStatusColor('succeeded') + ' p-4 rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-200 cursor-pointer border-2 border-green-200 hover:border-green-300'\"\n >\n <div class=\"text-sm\">Completed</div>\n <div class=\"text-2xl font-bold\">{{succeededCount}}</div>\n </button>\n <button \n @click=\"setStatusFilter('failed')\"\n :class=\"getStatusColor('failed') + ' p-4 rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-200 cursor-pointer border-2 border-red-200 hover:border-red-300'\"\n >\n <div class=\"text-sm\">Failed</div>\n <div class=\"text-2xl font-bold\">{{failedCount}}</div>\n </button>\n <button \n @click=\"setStatusFilter('cancelled')\"\n :class=\"getStatusColor('cancelled') + ' p-4 rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-200 cursor-pointer border-2 border-gray-200 hover:border-gray-300'\"\n >\n <div class=\"text-sm\">Cancelled</div>\n <div class=\"text-2xl font-bold\">{{cancelledCount}}</div>\n </button>\n </div>\n \n <!-- Grouped Task List -->\n <div class=\"mt-6\">\n <h2 class=\"text-lg font-semibold text-gray-700 mb-4\">Tasks by Name</h2>\n <ul class=\"divide-y divide-gray-200\">\n <li v-for=\"group in tasksByName\" :key=\"group.name\" class=\"p-4 group hover:border hover:rounded-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-200\">\n <div class=\"flex items-center justify-between mb-3 \">\n <div class=\"flex-1 cursor-pointer\" @click=\"openTaskGroupDetails(group)\">\n <div class=\"flex items-center gap-2\">\n <div class=\"font-medium text-lg group-hover:text-ultramarine-600 transition-colors\">{{ group.name }}</div>\n <svg class=\"w-4 h-4 text-gray-400 group-hover:text-ultramarine-600 transition-colors\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\"></path>\n </svg>\n </div>\n <div class=\"text-sm text-gray-500 group-hover:text-gray-700 transition-colors\">Total: {{ group.totalCount }} tasks</div>\n <div class=\"text-xs text-ultramarine-600 opacity-0 group-hover:opacity-100 transition-opacity mt-1\">\n Click to view details\n </div>\n </div>\n <div class=\"text-sm text-gray-500\">\n Last run: {{ group.lastRun ? new Date(group.lastRun).toLocaleString() : 'Never' }}\n </div>\n </div>\n \n <!-- Status Counts -->\n <div class=\"grid grid-cols-2 sm:grid-cols-4 gap-2\">\n <button \n @click.stop=\"openTaskGroupDetailsWithFilter(group, 'pending')\"\n class=\"bg-yellow-50 border border-yellow-200 rounded-md p-2 text-center shadow-sm hover:shadow-md transform hover:-translate-y-1 transition-all duration-200 cursor-pointer hover:border-yellow-300\"\n >\n <div class=\"text-xs text-yellow-600 font-medium\">Pending</div>\n <div class=\"text-lg font-bold text-yellow-700\">{{ group.statusCounts.pending || 0 }}</div>\n </button>\n <button \n @click.stop=\"openTaskGroupDetailsWithFilter(group, 'succeeded')\"\n class=\"bg-green-50 border border-green-200 rounded-md p-2 text-center shadow-sm hover:shadow-md transform hover:-translate-y-1 transition-all duration-200 cursor-pointer hover:border-green-300\"\n >\n <div class=\"text-xs text-green-600 font-medium\">Succeeded</div>\n <div class=\"text-lg font-bold text-green-700\">{{ group.statusCounts.succeeded || 0 }}</div>\n </button>\n <button \n @click.stop=\"openTaskGroupDetailsWithFilter(group, 'failed')\"\n class=\"bg-red-50 border border-red-200 rounded-md p-2 text-center shadow-sm hover:shadow-md transform hover:-translate-y-1 transition-all duration-200 cursor-pointer hover:border-red-300\"\n >\n <div class=\"text-xs text-red-600 font-medium\">Failed</div>\n <div class=\"text-lg font-bold text-red-700\">{{ group.statusCounts.failed || 0 }}</div>\n </button>\n <button \n @click.stop=\"openTaskGroupDetailsWithFilter(group, 'cancelled')\"\n class=\"bg-gray-50 border border-gray-200 rounded-md p-2 text-center shadow-sm hover:shadow-md transform hover:-translate-y-1 transition-all duration-200 cursor-pointer hover:border-gray-300\"\n >\n <div class=\"text-xs text-gray-600 font-medium\">Cancelled</div>\n <div class=\"text-lg font-bold text-gray-700\">{{ group.statusCounts.cancelled || 0 }}</div>\n </button>\n </div>\n </li>\n </ul>\n </div>\n </div>\n </div>\n\n <!-- Create Task Modal -->\n <modal v-if=\"showCreateTaskModal\" containerClass=\"!h-[90vh] !w-[90vw]\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"closeCreateTaskModal\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"space-y-4\">\n <h3 class=\"text-lg font-semibold text-gray-700 mb-4\">Create New Task</h3>\n \n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Task Name:</label>\n <input \n v-model=\"newTask.name\" \n type=\"text\" \n class=\"w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ultramarine-500\"\n placeholder=\"Enter task name\"\n >\n </div>\n \n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Scheduled Time:</label>\n <input \n v-model=\"newTask.scheduledAt\" \n type=\"datetime-local\" \n class=\"w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ultramarine-500\"\n >\n </div>\n \n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Parameters (JSON):</label>\n <textarea \n ref=\"parametersEditor\"\n class=\"w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ultramarine-500\"\n placeholder='{\"key\": \"value\"}'\n ></textarea>\n </div>\n \n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Repeat Interval (ms):</label>\n <input \n v-model=\"newTask.repeatInterval\" \n type=\"number\" \n min=\"0\"\n step=\"1000\"\n class=\"w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ultramarine-500\"\n placeholder=\"0 for no repetition\"\n >\n <p class=\"text-xs text-gray-500 mt-1\">Enter 0 or leave empty for no repetition. Use 1000 for 1 second, 60000 for 1 minute, etc.</p>\n </div>\n \n <div class=\"flex gap-2 pt-4\">\n <button \n @click=\"createTask\" \n class=\"flex-1 bg-ultramarine-600 text-white px-4 py-2 rounded-md hover:bg-ultramarine-700\"\n >\n Create Task\n </button>\n <button \n @click=\"closeCreateTaskModal\" \n class=\"flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400\"\n >\n Cancel\n </button>\n </div>\n </div>\n </template>\n </modal>\n</div>\n";
|
|
26106
|
+
module.exports = "<div class=\"p-4 space-y-6\">\n <div>\n <h1 class=\"text-2xl font-bold text-gray-700 mb-4\">Task Overview</h1>\n <div v-if=\"status == 'init'\">\n <img src=\"images/loader.gif\" />\n </div>\n <!-- Task List -->\n <div class=\"bg-white p-4 rounded-lg shadow\" v-if=\"status == 'loaded'\">\n <div class=\"mb-4\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Filter by Date:</label>\n <select v-model=\"selectedRange\" @change=\"updateDateRange\" class=\"border-gray-300 rounded-md shadow-sm w-full p-2\">\n <option v-for=\"option in dateFilters\" :key=\"option.value\" :value=\"option.value\">\n {{ option.label }}\n </option>\n </select>\n </div>\n <div class=\"mb-4\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Filter by Status:</label>\n <select v-model=\"selectedStatus\" @change=\"getTasks\" class=\"border-gray-300 rounded-md shadow-sm w-full p-2\">\n <option v-for=\"option in statusFilters\" :key=\"option.value\" :value=\"option.value\">\n {{ option.label }}\n </option>\n </select>\n </div>\n <div class=\"mb-4\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Search by Task Name:</label>\n <input \n v-model=\"searchQuery\" \n type=\"text\" \n @input=\"onSearchInput\"\n class=\"border-gray-300 rounded-md shadow-sm w-full p-2\"\n placeholder=\"Enter task name to search...\"\n >\n </div>\n <div class=\"mb-4\">\n <button\n @click=\"resetFilters\"\n class=\"w-full bg-gray-200 text-gray-700 hover:bg-gray-300 font-medium py-2 px-4 rounded-md transition\"\n >\n Reset Filters\n </button>\n </div>\n <div class=\"mb-6\">\n <button\n @click=\"openCreateTaskModal\"\n class=\"w-full bg-ultramarine-600 text-white hover:bg-ultramarine-700 font-medium py-2 px-4 rounded-md transition\"\n >\n Create New Task\n </button>\n </div>\n <!-- Summary Section -->\n <div class=\"grid grid-cols-2 sm:grid-cols-4 gap-4\">\n <button \n @click=\"setStatusFilter('pending')\"\n :class=\"getStatusColor('pending') + ' p-4 rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-200 cursor-pointer border-2 border-yellow-200 hover:border-yellow-300'\"\n >\n <div class=\"text-sm\">Scheduled</div>\n <div class=\"text-2xl font-bold\">{{pendingCount}}</div>\n </button>\n <button \n @click=\"setStatusFilter('succeeded')\"\n :class=\"getStatusColor('succeeded') + ' p-4 rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-200 cursor-pointer border-2 border-green-200 hover:border-green-300'\"\n >\n <div class=\"text-sm\">Completed</div>\n <div class=\"text-2xl font-bold\">{{succeededCount}}</div>\n </button>\n <button \n @click=\"setStatusFilter('failed')\"\n :class=\"getStatusColor('failed') + ' p-4 rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-200 cursor-pointer border-2 border-red-200 hover:border-red-300'\"\n >\n <div class=\"text-sm\">Failed</div>\n <div class=\"text-2xl font-bold\">{{failedCount}}</div>\n </button>\n <button \n @click=\"setStatusFilter('cancelled')\"\n :class=\"getStatusColor('cancelled') + ' p-4 rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-200 cursor-pointer border-2 border-gray-200 hover:border-gray-300'\"\n >\n <div class=\"text-sm\">Cancelled</div>\n <div class=\"text-2xl font-bold\">{{cancelledCount}}</div>\n </button>\n </div>\n \n <!-- Grouped Task List -->\n <div class=\"mt-6\">\n <h2 class=\"text-lg font-semibold text-gray-700 mb-4\">Tasks by Name</h2>\n <ul class=\"divide-y divide-gray-200\">\n <li v-for=\"group in tasksByName\" :key=\"group.name\" class=\"p-4 group hover:border hover:rounded-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-200\">\n <div class=\"flex items-center justify-between mb-3 \">\n <div class=\"flex-1 cursor-pointer\" @click=\"openTaskGroupDetails(group)\">\n <div class=\"flex items-center gap-2\">\n <div class=\"font-medium text-lg group-hover:text-ultramarine-600 transition-colors\">{{ group.name }}</div>\n <svg class=\"w-4 h-4 text-gray-400 group-hover:text-ultramarine-600 transition-colors\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\"></path>\n </svg>\n </div>\n <div class=\"text-sm text-gray-500 group-hover:text-gray-700 transition-colors\">Total: {{ group.totalCount }} tasks</div>\n <div class=\"text-xs text-ultramarine-600 opacity-0 group-hover:opacity-100 transition-opacity mt-1\">\n Click to view details\n </div>\n </div>\n <div class=\"text-sm text-gray-500\">\n Last run: {{ group.lastRun ? new Date(group.lastRun).toLocaleString() : 'Never' }}\n </div>\n </div>\n \n <!-- Status Counts -->\n <div class=\"grid grid-cols-2 sm:grid-cols-4 gap-2\">\n <button \n @click.stop=\"openTaskGroupDetailsWithFilter(group, 'pending')\"\n class=\"bg-yellow-50 border border-yellow-200 rounded-md p-2 text-center shadow-sm hover:shadow-md transform hover:-translate-y-1 transition-all duration-200 cursor-pointer hover:border-yellow-300\"\n >\n <div class=\"text-xs text-yellow-600 font-medium\">Pending</div>\n <div class=\"text-lg font-bold text-yellow-700\">{{ group.statusCounts.pending || 0 }}</div>\n </button>\n <button \n @click.stop=\"openTaskGroupDetailsWithFilter(group, 'succeeded')\"\n class=\"bg-green-50 border border-green-200 rounded-md p-2 text-center shadow-sm hover:shadow-md transform hover:-translate-y-1 transition-all duration-200 cursor-pointer hover:border-green-300\"\n >\n <div class=\"text-xs text-green-600 font-medium\">Succeeded</div>\n <div class=\"text-lg font-bold text-green-700\">{{ group.statusCounts.succeeded || 0 }}</div>\n </button>\n <button \n @click.stop=\"openTaskGroupDetailsWithFilter(group, 'failed')\"\n class=\"bg-red-50 border border-red-200 rounded-md p-2 text-center shadow-sm hover:shadow-md transform hover:-translate-y-1 transition-all duration-200 cursor-pointer hover:border-red-300\"\n >\n <div class=\"text-xs text-red-600 font-medium\">Failed</div>\n <div class=\"text-lg font-bold text-red-700\">{{ group.statusCounts.failed || 0 }}</div>\n </button>\n <button \n @click.stop=\"openTaskGroupDetailsWithFilter(group, 'cancelled')\"\n class=\"bg-gray-50 border border-gray-200 rounded-md p-2 text-center shadow-sm hover:shadow-md transform hover:-translate-y-1 transition-all duration-200 cursor-pointer hover:border-gray-300\"\n >\n <div class=\"text-xs text-gray-600 font-medium\">Cancelled</div>\n <div class=\"text-lg font-bold text-gray-700\">{{ group.statusCounts.cancelled || 0 }}</div>\n </button>\n </div>\n </li>\n </ul>\n </div>\n </div>\n </div>\n\n <!-- Create Task Modal -->\n <modal v-if=\"showCreateTaskModal\" containerClass=\"!h-[90vh] !w-[90vw]\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"closeCreateTaskModal\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"space-y-4\">\n <h3 class=\"text-lg font-semibold text-gray-700 mb-4\">Create New Task</h3>\n \n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Task Name:</label>\n <input \n v-model=\"newTask.name\" \n type=\"text\" \n class=\"w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ultramarine-500\"\n placeholder=\"Enter task name\"\n >\n </div>\n \n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Scheduled Time:</label>\n <input \n v-model=\"newTask.scheduledAt\" \n type=\"datetime-local\" \n class=\"w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ultramarine-500\"\n >\n </div>\n \n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Parameters (JSON):</label>\n <textarea \n ref=\"parametersEditor\"\n class=\"w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ultramarine-500\"\n placeholder='{\"key\": \"value\"}'\n ></textarea>\n </div>\n \n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Repeat Interval (ms):</label>\n <input \n v-model=\"newTask.repeatInterval\" \n type=\"number\" \n min=\"0\"\n step=\"1000\"\n class=\"w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ultramarine-500\"\n placeholder=\"0 for no repetition\"\n >\n <p class=\"text-xs text-gray-500 mt-1\">Enter 0 or leave empty for no repetition. Use 1000 for 1 second, 60000 for 1 minute, etc.</p>\n </div>\n \n <div class=\"flex gap-2 pt-4\">\n <button \n @click=\"createTask\" \n class=\"flex-1 bg-ultramarine-600 text-white px-4 py-2 rounded-md hover:bg-ultramarine-700\"\n >\n Create Task\n </button>\n <button \n @click=\"closeCreateTaskModal\" \n class=\"flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400\"\n >\n Cancel\n </button>\n </div>\n </div>\n </template>\n </modal>\n</div>\n";
|
|
25592
26107
|
|
|
25593
26108
|
/***/ },
|
|
25594
26109
|
|
|
@@ -36902,7 +37417,7 @@ var src_default = VueToastificationPlugin;
|
|
|
36902
37417
|
(module) {
|
|
36903
37418
|
|
|
36904
37419
|
"use strict";
|
|
36905
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.2.
|
|
37420
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.2.13","description":"A Mongoose-native MongoDB UI with schema-aware autocomplete, AI-assisted queries, and dashboards that understand your models - not just your data.","homepage":"https://mongoosestudio.app/","repository":{"type":"git","url":"https://github.com/mongoosejs/studio"},"license":"Apache-2.0","dependencies":{"@ai-sdk/anthropic":"2.x","@ai-sdk/google":"2.x","@ai-sdk/openai":"2.x","ai":"5.x","archetype":"0.13.1","csv-stringify":"6.3.0","ejson":"^2.2.3","extrovert":"^0.2.0","marked":"15.0.12","node-inspect-extracted":"3.x","tailwindcss":"3.4.0","vue":"3.x","vue-toastification":"^2.0.0-rc.5","webpack":"5.x","xss":"^1.0.15"},"peerDependencies":{"mongoose":"7.x || 8.x || ^9.0.0"},"optionalPeerDependencies":{"@mongoosejs/task":"0.5.x || 0.6.x"},"devDependencies":{"@masteringjs/eslint-config":"0.1.1","axios":"1.2.2","dedent":"^1.6.0","eslint":"9.30.0","express":"4.x","mocha":"10.2.0","mongodb-memory-server":"^11.0.1","mongoose":"9.x","sinon":"^21.0.1"},"scripts":{"lint":"eslint .","tailwind":"tailwindcss -o ./frontend/public/tw.css","tailwind:watch":"tailwindcss -o ./frontend/public/tw.css --watch","test":"mocha test/*.test.js","test:frontend":"mocha test/frontend/*.test.js"}}');
|
|
36906
37421
|
|
|
36907
37422
|
/***/ }
|
|
36908
37423
|
|
|
@@ -36918,12 +37433,6 @@ module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version"
|
|
|
36918
37433
|
/******/ if (cachedModule !== undefined) {
|
|
36919
37434
|
/******/ return cachedModule.exports;
|
|
36920
37435
|
/******/ }
|
|
36921
|
-
/******/ // Check if module exists (development only)
|
|
36922
|
-
/******/ if (__webpack_modules__[moduleId] === undefined) {
|
|
36923
|
-
/******/ var e = new Error("Cannot find module '" + moduleId + "'");
|
|
36924
|
-
/******/ e.code = 'MODULE_NOT_FOUND';
|
|
36925
|
-
/******/ throw e;
|
|
36926
|
-
/******/ }
|
|
36927
37436
|
/******/ // Create a new module (and put it into the cache)
|
|
36928
37437
|
/******/ var module = __webpack_module_cache__[moduleId] = {
|
|
36929
37438
|
/******/ // no module.id needed
|
|
@@ -36932,6 +37441,12 @@ module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version"
|
|
|
36932
37441
|
/******/ };
|
|
36933
37442
|
/******/
|
|
36934
37443
|
/******/ // Execute the module function
|
|
37444
|
+
/******/ if (!(moduleId in __webpack_modules__)) {
|
|
37445
|
+
/******/ delete __webpack_module_cache__[moduleId];
|
|
37446
|
+
/******/ var e = new Error("Cannot find module '" + moduleId + "'");
|
|
37447
|
+
/******/ e.code = 'MODULE_NOT_FOUND';
|
|
37448
|
+
/******/ throw e;
|
|
37449
|
+
/******/ }
|
|
36935
37450
|
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
36936
37451
|
/******/
|
|
36937
37452
|
/******/ // Return the exports of the module
|