@mongoosejs/studio 0.0.31 → 0.0.33

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.
@@ -19,23 +19,9 @@ module.exports = ({ db }) => async function getDashboard(params) {
19
19
 
20
20
  const dashboard = await Dashboard.findOne({ _id: dashboardId });
21
21
  if (evaluate) {
22
- const context = vm.createContext({ db });
23
22
  let result = null;
24
23
  try {
25
- result = await vm.runInContext(formatFunction(dashboard.code), context);
26
- if (result.$document?.model) {
27
- let schemaPaths = {};
28
- const Model = Dashboard.db.model(result.$document?.model);
29
- for (const path of Object.keys(Model.schema.paths)) {
30
- schemaPaths[path] = {
31
- instance: Model.schema.paths[path].instance,
32
- path,
33
- ref: Model.schema.paths[path].options?.ref,
34
- required: Model.schema.paths[path].options?.required
35
- };
36
- }
37
- result.$document.schemaPaths = schemaPaths;
38
- }
24
+ result = await dashboard.evaluate();
39
25
  } catch (error) {
40
26
  return { dashboard, error: { message: error.message } };
41
27
  }
@@ -44,8 +30,4 @@ module.exports = ({ db }) => async function getDashboard(params) {
44
30
  }
45
31
 
46
32
  return { dashboard };
47
- };
48
-
49
- const formatFunction = code => `(async function() {
50
- ${code}
51
- })();`
33
+ };
@@ -3,23 +3,30 @@
3
3
  const Archetype = require('archetype');
4
4
 
5
5
  const UpdateDashboardParams = new Archetype({
6
- dashboardId: {
7
- $type: 'string',
8
- $required: true
9
- },
10
- code: {
11
- $type: 'string',
12
- $required: true
13
- }
14
- }).compile('UpdateDashboardParams');
15
-
16
- module.exports = ({ db }) => async function updateDashboard(params) {
17
- const { dashboardId, code } = new UpdateDashboardParams(params);
6
+ dashboardId: {
7
+ $type: 'string',
8
+ $required: true
9
+ },
10
+ code: {
11
+ $type: 'string',
12
+ $required: true
13
+ }
14
+ }).compile('UpdateDashboardParams');
15
+
16
+ module.exports = ({ db }) => async function updateDashboard(params) {
17
+ const { dashboardId, code } = new UpdateDashboardParams(params);
18
+
19
+ const Dashboard = db.models[`__Studio_Dashboard`];
20
+
21
+ const doc = await Dashboard.
22
+ findByIdAndUpdate(dashboardId, { code }, { sanitizeFilter: true, returnDocument: 'after', overwriteImmutable: true });
18
23
 
19
- const Dashboard = db.models[`__Studio_Dashboard`];
20
-
21
- const doc = await Dashboard.
22
- findByIdAndUpdate(dashboardId, { code }, { sanitizeFilter: true, returnDocument: 'after', overwriteImmutable: true });
23
-
24
- return { doc };
25
- };
24
+ let result = null;
25
+ try {
26
+ result = await doc.evaluate();
27
+ } catch (error) {
28
+ return { doc, error: { message: error.message } };
29
+ }
30
+
31
+ return { doc, result };
32
+ };
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const mongoose = require('mongoose');
4
+ const vm = require('vm');
4
5
 
5
6
  const dashboardSchema = new mongoose.Schema({
6
7
  title: {
@@ -16,4 +17,29 @@ const dashboardSchema = new mongoose.Schema({
16
17
  }
17
18
  });
18
19
 
19
- module.exports = dashboardSchema;
20
+ dashboardSchema.methods.evaluate = async function evaluate() {
21
+ const context = vm.createContext({ db: this.constructor.db });
22
+ let result = null;
23
+ result = await vm.runInContext(formatFunction(this.code), context);
24
+ if (result.$document?.model) {
25
+ let schemaPaths = {};
26
+ const Model = this.constructor.db.model(result.$document?.model);
27
+ for (const path of Object.keys(Model.schema.paths)) {
28
+ schemaPaths[path] = {
29
+ instance: Model.schema.paths[path].instance,
30
+ path,
31
+ ref: Model.schema.paths[path].options?.ref,
32
+ required: Model.schema.paths[path].options?.required
33
+ };
34
+ }
35
+ result.$document.schemaPaths = schemaPaths;
36
+ }
37
+
38
+ return result;
39
+ };
40
+
41
+ module.exports = dashboardSchema;
42
+
43
+ const formatFunction = code => `(async function() {
44
+ ${code}
45
+ })();`
@@ -34,10 +34,10 @@ if (false) {} else {
34
34
  return client.post('/Dashboard/createDashboard', params).then(res => res.data);
35
35
  },
36
36
  getDashboard: function getDashboard(params) {
37
- return client.get('/Dashboard/getDashboard', params).then(res => res.data);
37
+ return client.put('/Dashboard/getDashboard', params).then(res => res.data);
38
38
  },
39
39
  getDashboards: function getDashboards(params) {
40
- return client.get('/Dashboard/getDashboards', params).then(res => res.data);
40
+ return client.put('/Dashboard/getDashboards', params).then(res => res.data);
41
41
  },
42
42
  updateDashboard: function updateDashboard(params) {
43
43
  return client.post('/Dashboard/updateDashboard', params).then(res => res.data);
@@ -429,7 +429,6 @@ module.exports = app => app.component('dashboard-result', {
429
429
  },
430
430
  methods: {
431
431
  getComponentForValue(value) {
432
- console.log('X', value);
433
432
  if (typeof value !== 'object' || value == null) {
434
433
  return 'dashboard-primitive';
435
434
  }
@@ -463,6 +462,7 @@ const template = __webpack_require__(/*! ./dashboard.html */ "./frontend/src/das
463
462
 
464
463
  module.exports = app => app.component('dashboard', {
465
464
  template: template,
465
+ props: ['dashboardId'],
466
466
  data: function() {
467
467
  return {
468
468
  status: 'loading',
@@ -477,12 +477,12 @@ module.exports = app => app.component('dashboard', {
477
477
  this.showEditor = !this.showEditor;
478
478
  },
479
479
  async updateCode(update) {
480
- this.code = update;
480
+ this.code = update.doc.code;
481
+ this.result = update.result;
481
482
  }
482
483
  },
483
484
  mounted: async function() {
484
- const dashboardId = this.$route.query.dashboardId;
485
- const { dashboard, result } = await api.Dashboard.getDashboard({ params: { dashboardId: dashboardId, evaluate: true } });
485
+ const { dashboard, result } = await api.Dashboard.getDashboard({ dashboardId: this.dashboardId, evaluate: true });
486
486
  if (!dashboard) {
487
487
  return;
488
488
  }
@@ -522,8 +522,11 @@ module.exports = app => app.component('edit-dashboard', {
522
522
  this.$emit('close')
523
523
  },
524
524
  async updateCode() {
525
- const { doc } = await api.Dashboard.updateDashboard({ dashboardId: this.dashboardId, code: this.editor.getValue() });
526
- this.$emit('update', doc.code);
525
+ const { doc, result } = await api.Dashboard.updateDashboard({
526
+ dashboardId: this.dashboardId,
527
+ code: this.editor.getValue()
528
+ });
529
+ this.$emit('update', { doc, result });
527
530
  this.editor.setValue(doc.code);
528
531
  this.closeEditor();
529
532
  }
@@ -662,7 +665,7 @@ appendCSS(__webpack_require__(/*! ./document-details.css */ "./frontend/src/docu
662
665
 
663
666
  module.exports = app => app.component('document-details', {
664
667
  template,
665
- props: ['document', 'schemaPaths', 'editting', 'changes'],
668
+ props: ['document', 'schemaPaths', 'editting', 'changes', 'invalid'],
666
669
  methods: {
667
670
  getComponentForPath(schemaPath) {
668
671
  if (schemaPath.instance === 'Array') {
@@ -680,6 +683,9 @@ module.exports = app => app.component('document-details', {
680
683
  if (path.instance === 'Array') {
681
684
  return 'edit-array';
682
685
  }
686
+ if (path.instance === 'Embedded') {
687
+ return 'edit-subdocument';
688
+ }
683
689
  return 'edit-default';
684
690
  },
685
691
  getValueForPath(path) {
@@ -860,19 +866,28 @@ appendCSS(__webpack_require__(/*! ./edit-array.css */ "./frontend/src/edit-array
860
866
  module.exports = app => app.component('edit-array', {
861
867
  template: template,
862
868
  props: ['value'],
863
- data: () => ({ currentValue: null }),
869
+ data: () => ({ currentValue: null, status: 'init' }),
864
870
  mounted() {
865
- this.currentValue = JSON.stringify(this.value, null, ' ').trim();
871
+ this.currentValue = this.value == null
872
+ ? '' + this.value
873
+ : JSON.stringify(this.value, null, ' ').trim();
866
874
  this.$refs.arrayEditor.value = this.currentValue;
867
875
  this.editor = CodeMirror.fromTextArea(this.$refs.arrayEditor, {
868
876
  mode: 'javascript',
869
877
  lineNumbers: true
870
878
  });
879
+ this.editor.on('change', ev => {
880
+ this.currentValue = this.editor.getValue();
881
+ });
882
+ this.status = 'loaded';
871
883
  },
872
884
  watch: {
873
885
  currentValue() {
886
+ if (this.status === 'init') {
887
+ return;
888
+ }
874
889
  try {
875
- this.$emit('input', eval(this.currentValue));
890
+ this.$emit('input', eval(`(${this.currentValue})`));
876
891
  } catch (err) {
877
892
  this.$emit('error', err);
878
893
  }
@@ -998,6 +1013,67 @@ module.exports = app => app.component('edit-number', {
998
1013
  }
999
1014
  });
1000
1015
 
1016
+ /***/ }),
1017
+
1018
+ /***/ "./frontend/src/edit-subdocument/edit-subdocument.js":
1019
+ /*!***********************************************************!*\
1020
+ !*** ./frontend/src/edit-subdocument/edit-subdocument.js ***!
1021
+ \***********************************************************/
1022
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1023
+
1024
+ "use strict";
1025
+
1026
+
1027
+ const template = __webpack_require__(/*! ./edit-subdocument.html */ "./frontend/src/edit-subdocument/edit-subdocument.html");
1028
+
1029
+ const { BSON, EJSON } = __webpack_require__(/*! bson */ "./node_modules/bson/lib/bson.cjs");
1030
+
1031
+ const ObjectId = new Proxy(BSON.ObjectId, {
1032
+ apply (target, thisArg, argumentsList) {
1033
+ return new target(...argumentsList);
1034
+ }
1035
+ });
1036
+
1037
+ module.exports = app => app.component('edit-subdocument', {
1038
+ template: template,
1039
+ props: ['value'],
1040
+ data: () => ({ currentValue: null, status: 'init' }),
1041
+ mounted() {
1042
+ this.currentValue = this.value == null
1043
+ ? '' + this.value
1044
+ : JSON.stringify(this.value, null, ' ').trim();
1045
+ this.$refs.editor.value = this.currentValue;
1046
+ this.editor = CodeMirror.fromTextArea(this.$refs.editor, {
1047
+ mode: 'javascript',
1048
+ lineNumbers: true
1049
+ });
1050
+ this.editor.on('change', ev => {
1051
+ this.currentValue = this.editor.getValue();
1052
+ });
1053
+ this.status = 'loaded';
1054
+ },
1055
+ watch: {
1056
+ currentValue() {
1057
+ if (this.status === 'init') {
1058
+ return;
1059
+ }
1060
+ try {
1061
+ this.$emit('input', eval(`(${this.currentValue})`));
1062
+ } catch (err) {
1063
+ console.log('Error', err);
1064
+ this.$emit('error', err);
1065
+ }
1066
+ }
1067
+ },
1068
+ beforeDestroy() {
1069
+ if (this.editor) {
1070
+ this.editor.toTextArea();
1071
+ }
1072
+ },
1073
+ emits: ['input', 'error']
1074
+ });
1075
+
1076
+
1001
1077
  /***/ }),
1002
1078
 
1003
1079
  /***/ "./frontend/src/export-query-results/export-query-results.js":
@@ -1703,7 +1779,7 @@ module.exports = [
1703
1779
  component: 'dashboards'
1704
1780
  },
1705
1781
  {
1706
- path: '/dashboard',
1782
+ path: '/dashboard/:dashboardId',
1707
1783
  name: 'dashboard',
1708
1784
  component: 'dashboard'
1709
1785
  }
@@ -2428,7 +2504,7 @@ module.exports = "<div>\n <div v-if=\"Array.isArray(result)\">\n <div v-for=
2428
2504
  /***/ ((module) => {
2429
2505
 
2430
2506
  "use strict";
2431
- module.exports = "<div class=\"dashboard px-1\">\n <div v-if=\"dashboard\" class=\"max-w-5xl mx-auto\">\n <div class=\"flex items-center w-full\">\n <h2 class=\"mt-4 mb-4 text-gray-900 font-semibold text-xl grow shrink\">{{dashboard.title}}</h2>\n <div>\n <button\n v-if=\"!showEditor\"\n @click=\"showEditor = true\"\n type=\"button\"\n class=\"rounded-md bg-teal-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-teal-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 h-[1em]\" /> Edit\n </button>\n </div>\n </div>\n <div v-if=\"!showEditor\" class=\"mt-4 mb-4\">\n <dashboard-result :result=\"result\"></dashboard-result>\n </div>\n <div v-if=\"showEditor\">\n <edit-dashboard :dashboardId=\"dashboard._id\" :code=\"code\" @close=\"showEditor=false;\" @update=\"updateCode\"></edit-dashboard>\n </div>\n \n </div>\n <div v-if=\"!dashboard && status === 'loaded'\">\n No dashboard with the given id could be found.\n </div>\n</div>";
2507
+ module.exports = "<div class=\"dashboard px-1\">\n <div v-if=\"dashboard\" class=\"max-w-5xl mx-auto\">\n <div class=\"flex items-center w-full\">\n <h2 class=\"mt-4 mb-4 text-gray-900 font-semibold text-xl grow shrink\">{{dashboard.title}}</h2>\n <div>\n <button\n v-if=\"!showEditor\"\n @click=\"showEditor = true\"\n type=\"button\"\n class=\"rounded-md bg-teal-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-teal-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 h-[1em]\" /> Edit\n </button>\n </div>\n </div>\n <div v-if=\"!showEditor\" class=\"mt-4 mb-4\">\n <dashboard-result :result=\"result\"></dashboard-result>\n </div>\n <div v-if=\"showEditor\">\n <edit-dashboard\n :dashboardId=\"dashboard._id\"\n :code=\"code\"\n @close=\"showEditor=false;\"\n @update=\"updateCode\"></edit-dashboard>\n </div>\n \n </div>\n <div v-if=\"!dashboard && status === 'loaded'\">\n No dashboard with the given id could be found.\n </div>\n</div>";
2432
2508
 
2433
2509
  /***/ }),
2434
2510
 
@@ -2450,7 +2526,7 @@ module.exports = "<div>\n <textarea ref=\"codeEditor\">{{code}}</textarea>\n
2450
2526
  /***/ ((module) => {
2451
2527
 
2452
2528
  "use strict";
2453
- module.exports = "<div class=\"dashboards max-w-5xl mx-auto mt-8\">\n <div v-if=\"status === 'loaded' && dashboards.length === 0\">\n <div class=\"text-center\">\n <h3 class=\"mt-2 text-sm font-semibold text-gray-900\">No dashboards yet</h3>\n <p class=\"mt-1 text-sm text-gray-500\">Get started by creating a new dashboard.</p>\n <div class=\"mt-6\">\n <button type=\"button\" class=\"inline-flex items-center rounded-md bg-teal-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-teal-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600\">\n <svg class=\"-ml-0.5 mr-1.5 h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z\" />\n </svg>\n New Dashboard\n </button>\n </div>\n </div>\n </div>\n\n\n <div class=\"px-4 sm:px-6 lg:px-8\">\n <div class=\"sm:flex sm:items-center\">\n <div class=\"sm:flex-auto\">\n <h1 class=\"text-base font-semibold leading-6 text-gray-900\">Dashboards</h1>\n </div>\n <div class=\"mt-4 sm:ml-16 sm:mt-0 sm:flex-none\">\n <button\n type=\"button\"\n @click=\"showCreateDashboardModal = true\"\n class=\"block rounded-md bg-teal-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-teal-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600\">Create New Dashboard</button>\n </div>\n </div>\n <div class=\"mt-8 flow-root\">\n <div class=\"-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8\">\n <div class=\"inline-block min-w-full py-2 align-middle\">\n <table class=\"min-w-full divide-y divide-gray-300\">\n <thead>\n <tr>\n <th scope=\"col\" class=\"py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 lg:pl-8\">Title</th>\n <th scope=\"col\" class=\"px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-[50%]\">Description</th>\n <th scope=\"col\" class=\"relative py-3.5 pl-3 pr-4 sm:pr-6 lg:pr-8\">\n </th>\n <th scope=\"col\" class=\"relative py-3.5 pl-3 pr-4 sm:pr-6 lg:pr-8\">\n </th>\n </tr>\n </thead>\n <tbody class=\"divide-y divide-gray-200 bg-white\">\n <tr v-for=\"dashboard in dashboards\">\n <td class=\"whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 lg:pl-8\">{{dashboard.title}}</td>\n <td class=\"whitespace-nowrap px-3 py-4 text-sm text-gray-500 truncate w-[50%]\">{{dashboard.description}}</td>\n <td class=\"relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8\">\n <router-link\n :to=\"'dashboard?edit=true&dashboardId=' + dashboard._id\"\n class=\"text-teal-600 hover:text-teal-900\">\n Edit\n </router-link>\n </td>\n <td class=\"relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8\">\n <router-link\n :to=\"'dashboard?edit=true&dashboardId=' + dashboard._id\"\n class=\"text-teal-600 hover:text-teal-900\">\n View\n </router-link>\n </td>\n </tr>\n \n <!-- More people... -->\n </tbody>\n </table>\n </div>\n </div>\n </div>\n </div>\n\n <modal v-if=\"showCreateDashboardModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"showCreateDashboardModal = false;\">&times;</div>\n \n <create-dashboard></create-dashboard>\n </template>\n </modal>\n</div>";
2529
+ module.exports = "<div class=\"dashboards max-w-5xl mx-auto mt-8\">\n <div v-if=\"status === 'loaded' && dashboards.length === 0\">\n <div class=\"text-center\">\n <h3 class=\"mt-2 text-sm font-semibold text-gray-900\">No dashboards yet</h3>\n <p class=\"mt-1 text-sm text-gray-500\">Get started by creating a new dashboard.</p>\n <div class=\"mt-6\">\n <button type=\"button\" class=\"inline-flex items-center rounded-md bg-teal-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-teal-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600\">\n <svg class=\"-ml-0.5 mr-1.5 h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z\" />\n </svg>\n New Dashboard\n </button>\n </div>\n </div>\n </div>\n\n\n <div class=\"px-4 sm:px-6 lg:px-8\">\n <div class=\"sm:flex sm:items-center\">\n <div class=\"sm:flex-auto\">\n <h1 class=\"text-base font-semibold leading-6 text-gray-900\">Dashboards</h1>\n </div>\n <div class=\"mt-4 sm:ml-16 sm:mt-0 sm:flex-none\">\n <button\n type=\"button\"\n @click=\"showCreateDashboardModal = true\"\n class=\"block rounded-md bg-teal-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-teal-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600\">Create New Dashboard</button>\n </div>\n </div>\n <div class=\"mt-8 flow-root\">\n <div class=\"-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8\">\n <div class=\"inline-block min-w-full py-2 align-middle\">\n <table class=\"min-w-full divide-y divide-gray-300\">\n <thead>\n <tr>\n <th scope=\"col\" class=\"py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 lg:pl-8\">Title</th>\n <th scope=\"col\" class=\"px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-[50%]\">Description</th>\n <th scope=\"col\" class=\"relative py-3.5 pl-3 pr-4 sm:pr-6 lg:pr-8\">\n </th>\n <th scope=\"col\" class=\"relative py-3.5 pl-3 pr-4 sm:pr-6 lg:pr-8\">\n </th>\n </tr>\n </thead>\n <tbody class=\"divide-y divide-gray-200 bg-white\">\n <tr v-for=\"dashboard in dashboards\">\n <td class=\"whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 lg:pl-8\">{{dashboard.title}}</td>\n <td class=\"whitespace-nowrap px-3 py-4 text-sm text-gray-500 truncate w-[50%]\">{{dashboard.description}}</td>\n <td class=\"relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8\">\n <router-link\n :to=\"'/dashboard/' + dashboard._id + '?edit=true'\"\n class=\"text-teal-600 hover:text-teal-900\">\n Edit\n </router-link>\n </td>\n <td class=\"relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8\">\n <router-link\n :to=\"'/dashboard/' + dashboard._id\"\n class=\"text-teal-600 hover:text-teal-900\">\n View\n </router-link>\n </td>\n </tr>\n \n <!-- More people... -->\n </tbody>\n </table>\n </div>\n </div>\n </div>\n </div>\n\n <modal v-if=\"showCreateDashboardModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"showCreateDashboardModal = false;\">&times;</div>\n \n <create-dashboard></create-dashboard>\n </template>\n </modal>\n</div>";
2454
2530
 
2455
2531
  /***/ }),
2456
2532
 
@@ -2527,7 +2603,7 @@ module.exports = ".document {\n max-width: 1200px;\n margin-left: auto;\n mar
2527
2603
  /***/ ((module) => {
2528
2604
 
2529
2605
  "use strict";
2530
- module.exports = "<div class=\"document\">\n <div class=\"document-menu\">\n <div class=\"left\">\n <button @click=\"$router.push('/model/' + this.model)\">\n &lsaquo; Back\n </button>\n </div>\n\n <div class=\"right\">\n <button\n v-if=\"!editting\"\n @click=\"editting = true\"\n type=\"button\"\n class=\"rounded-md bg-teal-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-teal-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 &times; Cancel\n </button>\n <button\n v-if=\"editting\"\n @click=\"shouldShowConfirmModal=true;\"\n type=\"button\"\n class=\"rounded-md bg-green-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\">\n <img src=\"images/save.svg\" class=\"inline\" /> Save\n </button>\n <button\n @click=\"remove\"\n type=\"button\"\n class=\"rounded-md bg-red-600 px-2.5 py-1.5 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-600\">\n <img src=\"images/delete.svg\" class=\"inline\" /> Delete\n </button>\n </div>\n </div>\n <div v-if=\"status === 'loaded'\">\n <document-details\n :document=\"document\"\n :schemaPaths=\"schemaPaths\"\n :editting=\"editting\"\n :changes=\"changes\"></document-details>\n <modal v-if=\"shouldShowConfirmModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowConfirmModal = false;\">&times;</div>\n <confirm-changes @close=\"shouldShowConfirmModal = false;\" @save=\"save\" :value=\"changes\"></confirm-changes>\n </template>\n </modal>\n </div>\n</div>\n";
2606
+ module.exports = "<div class=\"document\">\n <div class=\"document-menu\">\n <div class=\"left\">\n <button @click=\"$router.push('/model/' + this.model)\">\n &lsaquo; Back\n </button>\n </div>\n\n <div class=\"right\">\n <button\n v-if=\"!editting\"\n @click=\"editting = true\"\n type=\"button\"\n class=\"rounded-md bg-teal-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-teal-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 &times; Cancel\n </button>\n <button\n v-if=\"editting\"\n @click=\"shouldShowConfirmModal=true;\"\n type=\"button\"\n class=\"rounded-md bg-green-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600\">\n <img src=\"images/save.svg\" class=\"inline\" /> Save\n </button>\n <button\n @click=\"remove\"\n type=\"button\"\n class=\"rounded-md bg-red-600 px-2.5 py-1.5 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-600\">\n <img src=\"images/delete.svg\" class=\"inline\" /> Delete\n </button>\n </div>\n </div>\n <div v-if=\"status === 'loaded'\">\n <document-details\n :document=\"document\"\n :schemaPaths=\"schemaPaths\"\n :editting=\"editting\"\n :changes=\"changes\"\n :invalid=\"invalid\"></document-details>\n <modal v-if=\"shouldShowConfirmModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowConfirmModal = false;\">&times;</div>\n <confirm-changes @close=\"shouldShowConfirmModal = false;\" @save=\"save\" :value=\"changes\"></confirm-changes>\n </template>\n </modal>\n </div>\n</div>\n";
2531
2607
 
2532
2608
  /***/ }),
2533
2609
 
@@ -2549,7 +2625,7 @@ module.exports = ".edit-array button {\n margin-top: 0.5em;\n}";
2549
2625
  /***/ ((module) => {
2550
2626
 
2551
2627
  "use strict";
2552
- module.exports = "<div class=\"edit-array\">\n <textarea ref=\"arrayEditor\" v-model=\"currentValue\" class=\"w-full border border-gray-300 p-1 h-[300px]\"></textarea>\n</div>";
2628
+ module.exports = "<div class=\"edit-array\">\n <textarea\n ref=\"arrayEditor\"\n class=\"w-full border border-gray-300 p-1 h-[300px]\"></textarea>\n</div>";
2553
2629
 
2554
2630
  /***/ }),
2555
2631
 
@@ -2586,6 +2662,17 @@ module.exports = "<div>\n <input type=\"number\" :value=\"value\" @input=\"$emi
2586
2662
 
2587
2663
  /***/ }),
2588
2664
 
2665
+ /***/ "./frontend/src/edit-subdocument/edit-subdocument.html":
2666
+ /*!*************************************************************!*\
2667
+ !*** ./frontend/src/edit-subdocument/edit-subdocument.html ***!
2668
+ \*************************************************************/
2669
+ /***/ ((module) => {
2670
+
2671
+ "use strict";
2672
+ module.exports = "<div class=\"edit-subdocument\">\n <textarea\n ref=\"editor\"\n v-model=\"currentValue\"\n class=\"w-full border border-gray-300 p-1 h-[300px]\"></textarea>\n</div>";
2673
+
2674
+ /***/ }),
2675
+
2589
2676
  /***/ "./frontend/src/export-query-results/export-query-results.css":
2590
2677
  /*!********************************************************************!*\
2591
2678
  !*** ./frontend/src/export-query-results/export-query-results.css ***!
@@ -10478,6 +10565,7 @@ __webpack_require__(/*! ./edit-array/edit-array */ "./frontend/src/edit-array/ed
10478
10565
  __webpack_require__(/*! ./edit-default/edit-default */ "./frontend/src/edit-default/edit-default.js")(app);
10479
10566
  __webpack_require__(/*! ./edit-number/edit-number */ "./frontend/src/edit-number/edit-number.js")(app);
10480
10567
  __webpack_require__(/*! ./edit-date/edit-date */ "./frontend/src/edit-date/edit-date.js")(app);
10568
+ __webpack_require__(/*! ./edit-subdocument/edit-subdocument */ "./frontend/src/edit-subdocument/edit-subdocument.js")(app);
10481
10569
  __webpack_require__(/*! ./export-query-results/export-query-results */ "./frontend/src/export-query-results/export-query-results.js")(app);
10482
10570
  __webpack_require__(/*! ./list-array/list-array */ "./frontend/src/list-array/list-array.js")(app);
10483
10571
  __webpack_require__(/*! ./list-default/list-default */ "./frontend/src/list-default/list-default.js")(app);
@@ -16,7 +16,11 @@
16
16
  <dashboard-result :result="result"></dashboard-result>
17
17
  </div>
18
18
  <div v-if="showEditor">
19
- <edit-dashboard :dashboardId="dashboard._id" :code="code" @close="showEditor=false;" @update="updateCode"></edit-dashboard>
19
+ <edit-dashboard
20
+ :dashboardId="dashboard._id"
21
+ :code="code"
22
+ @close="showEditor=false;"
23
+ @update="updateCode"></edit-dashboard>
20
24
  </div>
21
25
 
22
26
  </div>
@@ -5,6 +5,7 @@ const template = require('./dashboard.html');
5
5
 
6
6
  module.exports = app => app.component('dashboard', {
7
7
  template: template,
8
+ props: ['dashboardId'],
8
9
  data: function() {
9
10
  return {
10
11
  status: 'loading',
@@ -19,12 +20,12 @@ module.exports = app => app.component('dashboard', {
19
20
  this.showEditor = !this.showEditor;
20
21
  },
21
22
  async updateCode(update) {
22
- this.code = update;
23
+ this.code = update.doc.code;
24
+ this.result = update.result;
23
25
  }
24
26
  },
25
27
  mounted: async function() {
26
- const dashboardId = this.$route.query.dashboardId;
27
- const { dashboard, result } = await api.Dashboard.getDashboard({ dashboardId: dashboardId, evaluate: true });
28
+ const { dashboard, result } = await api.Dashboard.getDashboard({ dashboardId: this.dashboardId, evaluate: true });
28
29
  if (!dashboard) {
29
30
  return;
30
31
  }
@@ -17,8 +17,11 @@ module.exports = app => app.component('edit-dashboard', {
17
17
  this.$emit('close')
18
18
  },
19
19
  async updateCode() {
20
- const { doc } = await api.Dashboard.updateDashboard({ dashboardId: this.dashboardId, code: this.editor.getValue() });
21
- this.$emit('update', doc.code);
20
+ const { doc, result } = await api.Dashboard.updateDashboard({
21
+ dashboardId: this.dashboardId,
22
+ code: this.editor.getValue()
23
+ });
24
+ this.$emit('update', { doc, result });
22
25
  this.editor.setValue(doc.code);
23
26
  this.closeEditor();
24
27
  }
@@ -12,7 +12,6 @@ module.exports = app => app.component('dashboard-result', {
12
12
  },
13
13
  methods: {
14
14
  getComponentForValue(value) {
15
- console.log('X', value);
16
15
  if (typeof value !== 'object' || value == null) {
17
16
  return 'dashboard-primitive';
18
17
  }
@@ -47,14 +47,14 @@
47
47
  <td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500 truncate w-[50%]">{{dashboard.description}}</td>
48
48
  <td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8">
49
49
  <router-link
50
- :to="'dashboard?edit=true&dashboardId=' + dashboard._id"
50
+ :to="'/dashboard/' + dashboard._id + '?edit=true'"
51
51
  class="text-teal-600 hover:text-teal-900">
52
52
  Edit
53
53
  </router-link>
54
54
  </td>
55
55
  <td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8">
56
56
  <router-link
57
- :to="'dashboard?edit=true&dashboardId=' + dashboard._id"
57
+ :to="'/dashboard/' + dashboard._id"
58
58
  class="text-teal-600 hover:text-teal-900">
59
59
  View
60
60
  </router-link>
@@ -41,7 +41,8 @@
41
41
  :document="document"
42
42
  :schemaPaths="schemaPaths"
43
43
  :editting="editting"
44
- :changes="changes"></document-details>
44
+ :changes="changes"
45
+ :invalid="invalid"></document-details>
45
46
  <modal v-if="shouldShowConfirmModal">
46
47
  <template v-slot:body>
47
48
  <div class="modal-exit" @click="shouldShowConfirmModal = false;">&times;</div>
@@ -9,7 +9,7 @@ appendCSS(require('./document-details.css'));
9
9
 
10
10
  module.exports = app => app.component('document-details', {
11
11
  template,
12
- props: ['document', 'schemaPaths', 'editting', 'changes'],
12
+ props: ['document', 'schemaPaths', 'editting', 'changes', 'invalid'],
13
13
  methods: {
14
14
  getComponentForPath(schemaPath) {
15
15
  if (schemaPath.instance === 'Array') {
@@ -27,6 +27,9 @@ module.exports = app => app.component('document-details', {
27
27
  if (path.instance === 'Array') {
28
28
  return 'edit-array';
29
29
  }
30
+ if (path.instance === 'Embedded') {
31
+ return 'edit-subdocument';
32
+ }
30
33
  return 'edit-default';
31
34
  },
32
35
  getValueForPath(path) {
@@ -1,3 +1,5 @@
1
1
  <div class="edit-array">
2
- <textarea ref="arrayEditor" v-model="currentValue" class="w-full border border-gray-300 p-1 h-[300px]"></textarea>
2
+ <textarea
3
+ ref="arrayEditor"
4
+ class="w-full border border-gray-300 p-1 h-[300px]"></textarea>
3
5
  </div>
@@ -16,19 +16,28 @@ appendCSS(require('./edit-array.css'));
16
16
  module.exports = app => app.component('edit-array', {
17
17
  template: template,
18
18
  props: ['value'],
19
- data: () => ({ currentValue: null }),
19
+ data: () => ({ currentValue: null, status: 'init' }),
20
20
  mounted() {
21
- this.currentValue = JSON.stringify(this.value, null, ' ').trim();
21
+ this.currentValue = this.value == null
22
+ ? '' + this.value
23
+ : JSON.stringify(this.value, null, ' ').trim();
22
24
  this.$refs.arrayEditor.value = this.currentValue;
23
25
  this.editor = CodeMirror.fromTextArea(this.$refs.arrayEditor, {
24
26
  mode: 'javascript',
25
27
  lineNumbers: true
26
28
  });
29
+ this.editor.on('change', ev => {
30
+ this.currentValue = this.editor.getValue();
31
+ });
32
+ this.status = 'loaded';
27
33
  },
28
34
  watch: {
29
35
  currentValue() {
36
+ if (this.status === 'init') {
37
+ return;
38
+ }
30
39
  try {
31
- this.$emit('input', eval(this.currentValue));
40
+ this.$emit('input', eval(`(${this.currentValue})`));
32
41
  } catch (err) {
33
42
  this.$emit('error', err);
34
43
  }
@@ -0,0 +1,6 @@
1
+ <div class="edit-subdocument">
2
+ <textarea
3
+ ref="editor"
4
+ v-model="currentValue"
5
+ class="w-full border border-gray-300 p-1 h-[300px]"></textarea>
6
+ </div>
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ const template = require('./edit-subdocument.html');
4
+
5
+ const { BSON, EJSON } = require('bson');
6
+
7
+ const ObjectId = new Proxy(BSON.ObjectId, {
8
+ apply (target, thisArg, argumentsList) {
9
+ return new target(...argumentsList);
10
+ }
11
+ });
12
+
13
+ module.exports = app => app.component('edit-subdocument', {
14
+ template: template,
15
+ props: ['value'],
16
+ data: () => ({ currentValue: null, status: 'init' }),
17
+ mounted() {
18
+ this.currentValue = this.value == null
19
+ ? '' + this.value
20
+ : JSON.stringify(this.value, null, ' ').trim();
21
+ this.$refs.editor.value = this.currentValue;
22
+ this.editor = CodeMirror.fromTextArea(this.$refs.editor, {
23
+ mode: 'javascript',
24
+ lineNumbers: true
25
+ });
26
+ this.editor.on('change', ev => {
27
+ this.currentValue = this.editor.getValue();
28
+ });
29
+ this.status = 'loaded';
30
+ },
31
+ watch: {
32
+ currentValue() {
33
+ if (this.status === 'init') {
34
+ return;
35
+ }
36
+ try {
37
+ this.$emit('input', eval(`(${this.currentValue})`));
38
+ } catch (err) {
39
+ console.log('Error', err);
40
+ this.$emit('error', err);
41
+ }
42
+ }
43
+ },
44
+ beforeDestroy() {
45
+ if (this.editor) {
46
+ this.editor.toTextArea();
47
+ }
48
+ },
49
+ emits: ['input', 'error']
50
+ });
@@ -30,6 +30,7 @@ require('./edit-array/edit-array')(app);
30
30
  require('./edit-default/edit-default')(app);
31
31
  require('./edit-number/edit-number')(app);
32
32
  require('./edit-date/edit-date')(app);
33
+ require('./edit-subdocument/edit-subdocument')(app);
33
34
  require('./export-query-results/export-query-results')(app);
34
35
  require('./list-array/list-array')(app);
35
36
  require('./list-default/list-default')(app);
@@ -27,7 +27,7 @@ module.exports = [
27
27
  component: 'dashboards'
28
28
  },
29
29
  {
30
- path: '/dashboard',
30
+ path: '/dashboard/:dashboardId',
31
31
  name: 'dashboard',
32
32
  component: 'dashboard'
33
33
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mongoosejs/studio",
3
- "version": "0.0.31",
3
+ "version": "0.0.33",
4
4
  "dependencies": {
5
5
  "archetype": "0.13.0",
6
6
  "csv-stringify": "6.3.0",