@mongoosejs/studio 0.0.22 → 0.0.24

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.
Files changed (36) hide show
  1. package/backend/actions/Dashboard/getDashboard.js +18 -0
  2. package/backend/actions/Dashboard/index.js +3 -1
  3. package/backend/actions/Dashboard/updateDashboard.js +25 -0
  4. package/backend/index.js +6 -2
  5. package/frontend/public/app.js +405 -29759
  6. package/frontend/public/index.html +3 -0
  7. package/frontend/public/tw.css +119 -0
  8. package/frontend/src/api.js +12 -0
  9. package/frontend/src/create-document/create-document.html +20 -1
  10. package/frontend/src/create-document/create-document.js +13 -27
  11. package/frontend/src/dashboard/dashboard.html +13 -4
  12. package/frontend/src/dashboard/dashboard.js +25 -11
  13. package/frontend/src/dashboard/edit-dashboard/edit-dashboard.html +5 -0
  14. package/frontend/src/dashboard/edit-dashboard/edit-dashboard.js +48 -0
  15. package/frontend/src/dashboards/dashboards.html +5 -0
  16. package/frontend/src/dashboards/dashboards.js +20 -0
  17. package/frontend/src/document/confirm-changes/confirm-changes.html +18 -0
  18. package/frontend/src/document/confirm-changes/confirm-changes.js +24 -0
  19. package/frontend/src/document/document.html +11 -5
  20. package/frontend/src/document/document.js +7 -1
  21. package/frontend/src/edit-array/edit-array.html +1 -7
  22. package/frontend/src/edit-array/edit-array.js +27 -9
  23. package/frontend/src/edit-default/edit-default.html +1 -1
  24. package/frontend/src/index.js +3 -1
  25. package/frontend/src/models/models.css +0 -2
  26. package/frontend/src/models/models.js +0 -4
  27. package/frontend/src/routes.js +5 -0
  28. package/package.json +1 -6
  29. package/frontend/src/dashboard-details/dashboard-details.html +0 -8
  30. package/frontend/src/dashboard-details/dashboard-details.js +0 -10
  31. package/logs/COUNT_20230524-154120-151469/operation.log +0 -8
  32. package/logs/COUNT_20230524-154408-077670/operation.log +0 -22
  33. package/logs/COUNT_20230524-154414-431706/operation.log +0 -8
  34. package/logs/COUNT_20230524-155000-297076/operation.log +0 -8
  35. package/logs/LOAD_20230524-155832-351763/checkpoint.csv +0 -1
  36. package/logs/LOAD_20230524-155832-351763/operation.log +0 -23
@@ -10,9 +10,12 @@
10
10
  <link rel="stylesheet" href="https://unpkg.com/prismjs@1.29.0/themes/prism.css"/>
11
11
  <link rel="stylesheet" href="tw.css">
12
12
  <link rel="stylesheet" href="vanillatoasts/vanillatoasts.css">
13
+ <link rel="stylesheet" href="https://unpkg.com/codemirror@5.65.16/lib/codemirror.css">
13
14
  <script src="https://unpkg.com/vue@3.x"></script>
14
15
  <script src="https://unpkg.com/vue-router@4.0.10"></script>
15
16
  <script src="https://unpkg.com/chart.js@4.2.0/dist/chart.umd.js"></script>
17
+ <script src="https://unpkg.com/codemirror@5.65.16/lib/codemirror.js"></script>
18
+ <script src="https://unpkg.com/codemirror@5.65.16/mode/javascript/javascript.js"></script>
16
19
  </head>
17
20
 
18
21
  <body>
@@ -578,6 +578,10 @@ video {
578
578
  }
579
579
  }
580
580
 
581
+ .fixed {
582
+ position: fixed;
583
+ }
584
+
581
585
  .relative {
582
586
  position: relative;
583
587
  }
@@ -602,6 +606,22 @@ video {
602
606
  margin-bottom: 0.5rem;
603
607
  }
604
608
 
609
+ .mb-\[-1px\] {
610
+ margin-bottom: -1px;
611
+ }
612
+
613
+ .ml-3 {
614
+ margin-left: 0.75rem;
615
+ }
616
+
617
+ .mt-1 {
618
+ margin-top: 0.25rem;
619
+ }
620
+
621
+ .mt-2 {
622
+ margin-top: 0.5rem;
623
+ }
624
+
605
625
  .mt-4 {
606
626
  margin-top: 1rem;
607
627
  }
@@ -630,6 +650,14 @@ video {
630
650
  height: 1.25rem;
631
651
  }
632
652
 
653
+ .h-8 {
654
+ height: 2rem;
655
+ }
656
+
657
+ .h-\[300px\] {
658
+ height: 300px;
659
+ }
660
+
633
661
  .h-\[calc\(100vh-55px\)\] {
634
662
  height: calc(100vh - 55px);
635
663
  }
@@ -642,6 +670,10 @@ video {
642
670
  width: 1.25rem;
643
671
  }
644
672
 
673
+ .w-64 {
674
+ width: 16rem;
675
+ }
676
+
645
677
  .w-full {
646
678
  width: 100%;
647
679
  }
@@ -650,6 +682,10 @@ video {
650
682
  flex: 1 1 0%;
651
683
  }
652
684
 
685
+ .flex-shrink-0 {
686
+ flex-shrink: 0;
687
+ }
688
+
653
689
  .flex-grow {
654
690
  flex-grow: 1;
655
691
  }
@@ -658,6 +694,10 @@ video {
658
694
  flex-grow: 1;
659
695
  }
660
696
 
697
+ .list-disc {
698
+ list-style-type: disc;
699
+ }
700
+
661
701
  .flex-row {
662
702
  flex-direction: row;
663
703
  }
@@ -670,6 +710,10 @@ video {
670
710
  align-items: center;
671
711
  }
672
712
 
713
+ .justify-end {
714
+ justify-content: flex-end;
715
+ }
716
+
673
717
  .gap-2 {
674
718
  gap: 0.5rem;
675
719
  }
@@ -682,6 +726,12 @@ video {
682
726
  row-gap: 1.75rem;
683
727
  }
684
728
 
729
+ .space-y-1 > :not([hidden]) ~ :not([hidden]) {
730
+ --tw-space-y-reverse: 0;
731
+ margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
732
+ margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));
733
+ }
734
+
685
735
  .overflow-y-auto {
686
736
  overflow-y: auto;
687
737
  }
@@ -708,6 +758,14 @@ video {
708
758
  border-bottom-right-radius: 0.375rem;
709
759
  }
710
760
 
761
+ .rounded-tl-md {
762
+ border-top-left-radius: 0.375rem;
763
+ }
764
+
765
+ .rounded-tr-md {
766
+ border-top-right-radius: 0.375rem;
767
+ }
768
+
711
769
  .border {
712
770
  border-width: 1px;
713
771
  }
@@ -725,6 +783,11 @@ video {
725
783
  border-color: rgb(229 231 235 / var(--tw-border-opacity));
726
784
  }
727
785
 
786
+ .border-gray-300 {
787
+ --tw-border-opacity: 1;
788
+ border-color: rgb(209 213 219 / var(--tw-border-opacity));
789
+ }
790
+
728
791
  .border-teal-500 {
729
792
  --tw-border-opacity: 1;
730
793
  border-color: rgb(0 208 201 / var(--tw-border-opacity));
@@ -744,6 +807,11 @@ video {
744
807
  background-color: rgb(22 163 74 / var(--tw-bg-opacity));
745
808
  }
746
809
 
810
+ .bg-red-50 {
811
+ --tw-bg-opacity: 1;
812
+ background-color: rgb(254 242 242 / var(--tw-bg-opacity));
813
+ }
814
+
747
815
  .bg-red-600 {
748
816
  --tw-bg-opacity: 1;
749
817
  background-color: rgb(220 38 38 / var(--tw-bg-opacity));
@@ -782,6 +850,10 @@ video {
782
850
  padding: 0.5rem;
783
851
  }
784
852
 
853
+ .p-4 {
854
+ padding: 1rem;
855
+ }
856
+
785
857
  .px-1 {
786
858
  padding-left: 0.25rem;
787
859
  padding-right: 0.25rem;
@@ -816,6 +888,10 @@ video {
816
888
  padding-left: 0.5rem;
817
889
  }
818
890
 
891
+ .pl-5 {
892
+ padding-left: 1.25rem;
893
+ }
894
+
819
895
  .pr-2 {
820
896
  padding-right: 0.5rem;
821
897
  }
@@ -846,6 +922,11 @@ video {
846
922
  font-weight: 600;
847
923
  }
848
924
 
925
+ .text-black {
926
+ --tw-text-opacity: 1;
927
+ color: rgb(0 0 0 / var(--tw-text-opacity));
928
+ }
929
+
849
930
  .text-gray-400 {
850
931
  --tw-text-opacity: 1;
851
932
  color: rgb(156 163 175 / var(--tw-text-opacity));
@@ -861,11 +942,31 @@ video {
861
942
  color: rgb(55 65 81 / var(--tw-text-opacity));
862
943
  }
863
944
 
945
+ .text-gray-800 {
946
+ --tw-text-opacity: 1;
947
+ color: rgb(31 41 55 / var(--tw-text-opacity));
948
+ }
949
+
864
950
  .text-gray-900 {
865
951
  --tw-text-opacity: 1;
866
952
  color: rgb(17 24 39 / var(--tw-text-opacity));
867
953
  }
868
954
 
955
+ .text-red-400 {
956
+ --tw-text-opacity: 1;
957
+ color: rgb(248 113 113 / var(--tw-text-opacity));
958
+ }
959
+
960
+ .text-red-700 {
961
+ --tw-text-opacity: 1;
962
+ color: rgb(185 28 28 / var(--tw-text-opacity));
963
+ }
964
+
965
+ .text-red-800 {
966
+ --tw-text-opacity: 1;
967
+ color: rgb(153 27 27 / var(--tw-text-opacity));
968
+ }
969
+
869
970
  .text-sky-800 {
870
971
  --tw-text-opacity: 1;
871
972
  color: rgb(7 89 133 / var(--tw-text-opacity));
@@ -882,6 +983,10 @@ video {
882
983
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
883
984
  }
884
985
 
986
+ .outline-0 {
987
+ outline-width: 0px;
988
+ }
989
+
885
990
  .outline-gray-300 {
886
991
  outline-color: #d1d5db;
887
992
  }
@@ -918,6 +1023,16 @@ video {
918
1023
  border-color: rgb(209 213 219 / var(--tw-border-opacity));
919
1024
  }
920
1025
 
1026
+ .hover\:bg-gray-200:hover {
1027
+ --tw-bg-opacity: 1;
1028
+ background-color: rgb(229 231 235 / var(--tw-bg-opacity));
1029
+ }
1030
+
1031
+ .hover\:bg-gray-300:hover {
1032
+ --tw-bg-opacity: 1;
1033
+ background-color: rgb(209 213 219 / var(--tw-bg-opacity));
1034
+ }
1035
+
921
1036
  .hover\:bg-gray-50:hover {
922
1037
  --tw-bg-opacity: 1;
923
1038
  background-color: rgb(249 250 251 / var(--tw-bg-opacity));
@@ -969,6 +1084,10 @@ video {
969
1084
  outline-offset: 2px;
970
1085
  }
971
1086
 
1087
+ .focus-visible\:outline-gray-300:focus-visible {
1088
+ outline-color: #d1d5db;
1089
+ }
1090
+
972
1091
  .focus-visible\:outline-green-600:focus-visible {
973
1092
  outline-color: #16a34a;
974
1093
  }
@@ -20,8 +20,14 @@ if (typeof config__setAuthorizationHeaderFrom === 'string' && config__setAuthori
20
20
 
21
21
  if (config__isLambda) {
22
22
  exports.Dashboard = {
23
+ getDashboard(params) {
24
+ return client.post('', { action: 'Dashboard.getDashboard', ...params }).then(res => res.data);
25
+ },
23
26
  getDashboards(params) {
24
27
  return client.post('', { action: 'Dashboard.getDashboards', ...params }).then(res => res.data);
28
+ },
29
+ updateDashboard(params) {
30
+ return client.post('', { action: 'Dashboard.updateDashboard', ...params}).then(res => res.data);
25
31
  }
26
32
  }
27
33
  exports.Model = {
@@ -52,9 +58,15 @@ if (config__isLambda) {
52
58
  };
53
59
  } else {
54
60
  exports.Dashboard = {
61
+ getDashboard: function getDashboard(params) {
62
+ return client.get('/Dashboard/getDashboard', params).then(res => res.data);
63
+ },
55
64
  getDashboards: function getDashboards(params) {
56
65
  return client.get('/Dashboard/getDashboards', params).then(res => res.data);
57
66
  },
67
+ updateDashboard: function updateDashboard(params) {
68
+ return client.post('/Dashboard/updateDashboard', params).then(res => res.data);
69
+ }
58
70
  }
59
71
  exports.Model = {
60
72
  createChart: function (params) {
@@ -1,6 +1,25 @@
1
1
  <div>
2
2
  <div class="mb-2">
3
- <textarea class="border border-gray-200 p-2" ref="codeEditor" v-model="documentData"></textarea>
3
+ <textarea class="border border-gray-200 p-2 h-[300px] w-full" ref="codeEditor"></textarea>
4
4
  </div>
5
5
  <button @click="createDocument()" 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">Submit</button>
6
+ <div v-if="errors.length > 0" class="rounded-md bg-red-50 p-4 mt-1">
7
+ <div class="flex">
8
+ <div class="flex-shrink-0">
9
+ <svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
10
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd" />
11
+ </svg>
12
+ </div>
13
+ <div class="ml-3">
14
+ <h3 class="text-sm font-medium text-red-800">There were {{errors.length}} errors with your submission</h3>
15
+ <div class="mt-2 text-sm text-red-700">
16
+ <ul role="list" class="list-disc space-y-1 pl-5">
17
+ <li v-for="error in errors">
18
+ {{error}}
19
+ </li>
20
+ </ul>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ </div>
6
25
  </div>
@@ -1,10 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const api = require('../api');
4
- const { EditorState } = require('@codemirror/state');
5
- const { lineNumbers } = require('@codemirror/view')
6
- const { EditorView, basicSetup } = require('codemirror');
7
- const { javascript } = require('@codemirror/lang-javascript');
8
4
 
9
5
  const { BSON, EJSON } = require('bson');
10
6
 
@@ -26,23 +22,29 @@ module.exports = app => app.component('create-document', {
26
22
  data: function() {
27
23
  return {
28
24
  documentData: '',
29
- editor: null
25
+ editor: null,
26
+ errors: []
30
27
  }
31
28
  },
32
29
  methods: {
33
30
  async createDocument() {
34
- const data = EJSON.serialize(eval(`(${this.documentData})`));
31
+ const data = EJSON.serialize(eval(`(${this.editor.getValue()})`));
35
32
  const { doc } = await api.Model.createDocument({ model: this.currentModel, data }).catch(err => {
36
33
  if (err.response?.data?.message) {
34
+ console.log(err.response.data);
35
+ const message = err.response.data.message.split(": ").slice(1).join(": ");
36
+ this.errors = message.split(',').map(error => {
37
+ return error.split(': ').slice(1).join(': ').trim();
38
+ })
37
39
  throw new Error(err.response?.data?.message);
38
40
  }
39
41
  throw err;
40
42
  });
43
+ this.errors.length = 0;
41
44
  this.$emit('close', doc);
42
45
  },
43
46
  },
44
47
  mounted: function() {
45
- console.log(this.currentModel, this.paths);
46
48
  const requiredPaths = this.paths.filter(x => x.required);
47
49
  this.documentData = `{\n`;
48
50
  for (let i = 0; i < requiredPaths.length; i++) {
@@ -50,26 +52,10 @@ module.exports = app => app.component('create-document', {
50
52
  this.documentData += ` ${requiredPaths[i].path}: ${isLast ? '': ','}\n`
51
53
  }
52
54
  this.documentData += '}';
53
-
54
- this.editor = new EditorView({
55
- state: EditorState.create({
56
- doc: this.documentData,
57
- extensions: [
58
- basicSetup,
59
- javascript(),
60
- // history(),
61
- EditorView.updateListener.of((v) => {
62
- // Your update logic here
63
- }),
64
- // keymap.of(historyKeymap)
65
- ]
66
- }),
67
- parent: this.$refs.codeEditor
55
+ this.$refs.codeEditor.value = this.documentData;
56
+ this.editor = CodeMirror.fromTextArea(this.$refs.codeEditor, {
57
+ mode: 'javascript',
58
+ lineNumbers: true
68
59
  });
69
60
  },
70
- beforeDestroy() {
71
- if (this.editor) {
72
- this.editor.toTextArea();
73
- }
74
- }
75
61
  })
@@ -1,8 +1,17 @@
1
1
  <div class="dashboard">
2
- <div v-if="!dashboard">
3
- <div v-for="dashboard in dashboards" :key="dashboard._id">
4
- {{dashboard.name}}, ID: {{ dashboard._id }}
2
+ <div v-if="dashboard">
3
+ <div>
4
+ <h2>{{name}}</h2>
5
5
  </div>
6
+ <div>
7
+ <pre>{{code}}</pre>
8
+ <button v-if="!showEditor" @click="toggleEditor" style="color: black;margin-right: 0.5em">Edit</button>
9
+ </div>
10
+ <div v-if="showEditor">
11
+ <edit-dashboard :dashboardId="dashboard._id" :code="code" @close="showEditor=false;" @update="updateCode"></edit-dashboard>
12
+ </div>
13
+ </div>
14
+ <div v-if="!dashboard && status === 'loaded'">
15
+ No dashboard with the given id could be found.
6
16
  </div>
7
- <dashboard-details v-if="dashboard" :dashboard="dashboard"></dashboard-details>
8
17
  </div>
@@ -3,20 +3,34 @@
3
3
  const api = require('../api');
4
4
  const template = require('./dashboard.html');
5
5
 
6
-
7
6
  module.exports = app => app.component('dashboard', {
8
7
  template: template,
9
- data: () => ({
10
- dashboards: [],
11
- dashboard: null
12
- }),
13
- async mounted() {
14
- const { dashboards } = await api.Dashboard.getDashboards();
15
- this.dashboards = dashboards;
16
- if (!this.$route.query.dashboardId) {
8
+ data: function() {
9
+ return {
10
+ status: 'loading',
11
+ code: '',
12
+ name: '',
13
+ showEditor: false,
14
+ dashboard: null
15
+ }
16
+ },
17
+ methods: {
18
+ toggleEditor() {
19
+ this.showEditor = !this.showEditor;
20
+ },
21
+ async updateCode(update) {
22
+ this.code = update;
23
+ }
24
+ },
25
+ mounted: async function() {
26
+ const dashboardId = this.$route.query.dashboardId;
27
+ const { dashboard } = await api.Dashboard.getDashboard({ params: { dashboardId: dashboardId } });
28
+ if (!dashboard) {
17
29
  return;
18
30
  }
19
- this.dashboard = dashboards.find(x => x._id.toString() == this.$route.query.dashboardId);
31
+ this.dashboard = dashboard;
32
+ this.name = this.dashboard.name;
33
+ this.code = this.dashboard.code;
20
34
  this.status = 'loaded';
21
- },
35
+ }
22
36
  });
@@ -0,0 +1,5 @@
1
+ <div>
2
+ <textarea ref="codeEditor">{{code}}</textarea>
3
+ <button @click="updateCode" style="color: black;margin-right: 0.5em">Submit</button>
4
+ <button @click="closeEditor" class="gray" style="margin-right: 0.5em">Cancel</button>
5
+ </div>
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ const api = require('../../api');
4
+ const template = require('./edit-dashboard.html');
5
+
6
+ module.exports = app => app.component('edit-dashboard', {
7
+ template: template,
8
+ props: ['dashboardId', 'code'],
9
+ data: function() {
10
+ return {
11
+ status: 'loading',
12
+ editor: null,
13
+ }
14
+ },
15
+ methods: {
16
+ closeEditor() {
17
+ this.$emit('close')
18
+ },
19
+ async updateCode() {
20
+ const { doc } = await api.Dashboard.updateDashboard({ dashboardId: this.dashboardId, code: this.editor.getValue() });
21
+ this.$emit('update', doc.code);
22
+ this.editor.setValue(doc.code);
23
+ this.closeEditor();
24
+ }
25
+ },
26
+ mounted: async function() {
27
+ this.editor = CodeMirror.fromTextArea(this.$refs.codeEditor, {
28
+ mode: 'javascript',
29
+ lineNumbers: true,
30
+ indentUnit: 4,
31
+ smartIndent: true,
32
+ tabsize: 4,
33
+ indentWithTabs: true,
34
+ cursorBlinkRate: 300,
35
+ lineWrapping: true,
36
+ showCursorWhenSelecting: true,
37
+ });
38
+ // this.editor.setValue(this.code);
39
+ // this.editor.setSize(300, 300); // Ensure the editor has a fixed height
40
+
41
+ // this.editor.setCursor(this.editor.lineCount() - 1, this.editor.getLine(this.editor.lineCount() - 1).length);
42
+
43
+ this.editor.focus();
44
+ // this.editor.refresh(); // if anything weird happens on load, this usually fixes it. However, this breaks it in this case.
45
+
46
+
47
+ }
48
+ });
@@ -0,0 +1,5 @@
1
+ <div class="dashboards">
2
+ <div v-for="dashboard in dashboards" :key="dashboard._id" @click="$router.push('dashboard?dashboardId=' + dashboard._id)">
3
+ {{dashboard.name}}, ID: {{ dashboard._id }}
4
+ </div>
5
+ </div>
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ const api = require('../api');
4
+ const template = require('./dashboards.html');
5
+
6
+
7
+ module.exports = app => app.component('dashboards', {
8
+ template: template,
9
+ data: () => ({
10
+ dashboards: [],
11
+ }),
12
+ async mounted() {
13
+ const { dashboards } = await api.Dashboard.getDashboards();
14
+ this.dashboards = dashboards;
15
+ if (!this.$route.query.dashboardId) {
16
+ return;
17
+ }
18
+ this.status = 'loaded';
19
+ },
20
+ });
@@ -0,0 +1,18 @@
1
+ <div>
2
+ <h2>
3
+ Are you sure you want to save the following changes?
4
+ </h2>
5
+ <pre><code ref="code" class="language-javascript" v-text="displayValue"></code></pre>
6
+ <div class="flex gap-2 mt-2">
7
+ <async-button
8
+ 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"
9
+ @click="startSave">
10
+ Confirm
11
+ </async-button>
12
+ <button
13
+ class="rounded-md bg-gray-200 px-2.5 py-1.5 text-sm font-semibold text-black shadow-sm hover:bg-gray-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-300"
14
+ @click="closeConfirm">
15
+ Cancel
16
+ </button>
17
+ </div>
18
+ </div>
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ const template = require('./confirm-changes.html');
4
+
5
+ module.exports = app => app.component('confirm-changes', {
6
+ template: template,
7
+ props: ['value'],
8
+ computed: {
9
+ displayValue() {
10
+ return JSON.stringify(this.value, null, ' ').trim();
11
+ }
12
+ },
13
+ methods: {
14
+ closeConfirm() {
15
+ this.$emit('close')
16
+ },
17
+ startSave() {
18
+ this.$emit('save');
19
+ }
20
+ },
21
+ mounted() {
22
+ Prism.highlightElement(this.$refs.code);
23
+ }
24
+ });
@@ -16,14 +16,14 @@
16
16
  </button>
17
17
  <button
18
18
  v-if="editting"
19
- @click="save"
19
+ @click="editting = false"
20
20
  type="button"
21
21
  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">
22
22
  &times; Cancel
23
23
  </button>
24
24
  <button
25
25
  v-if="editting"
26
- @click="save"
26
+ @click="shouldShowConfirmModal=true;"
27
27
  type="button"
28
28
  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">
29
29
  <img src="images/save.svg" class="inline" /> Save
@@ -42,14 +42,14 @@
42
42
  {{path.path}}
43
43
  <span class="path-type">
44
44
  ({{(path.instance || 'unknown').toLowerCase()}})
45
- </span>
46
-
45
+ </span>
47
46
  </div>
48
47
  <div v-if="editting && path.path !== '_id'">
49
48
  <component
50
49
  :is="getEditComponentForPath(path)"
51
50
  :value="getEditValueForPath(path)"
52
- @input="changes[path.path] = $event;"
51
+ @input="changes[path.path] = $event; delete invalid[path.path];"
52
+ @error="invalid[path.path] = $event;"
53
53
  >
54
54
  </component>
55
55
  </div>
@@ -71,5 +71,11 @@
71
71
  {{path.value}}
72
72
  </div>
73
73
  </div>
74
+ <modal v-if="shouldShowConfirmModal">
75
+ <template v-slot:body>
76
+ <div class="modal-exit" @click="shouldShowConfirmModal = false;">&times;</div>
77
+ <confirm-changes @close="shouldShowConfirmModal = false;" @save="save" :value="changes"></confirm-changes>
78
+ </template>
79
+ </modal>
74
80
  </div>
75
81
  </div>
@@ -17,8 +17,10 @@ module.exports = app => app.component('document', {
17
17
  status: 'init',
18
18
  document: null,
19
19
  changes: {},
20
+ invalid: {},
20
21
  editting: false,
21
22
  virtuals: [],
23
+ shouldShowConfirmModal: false
22
24
  }),
23
25
  async mounted() {
24
26
  window.pageState = this;
@@ -76,6 +78,9 @@ module.exports = app => app.component('document', {
76
78
  this.editting = false;
77
79
  },
78
80
  async save() {
81
+ if (Object.keys(this.invalid).length > 0) {
82
+ throw new Error('Invalid paths: ' + Object.keys(this.invalid).join(', '));
83
+ }
79
84
  const { doc } = await api.Model.updateDocument({
80
85
  model: this.model,
81
86
  _id: this.document._id,
@@ -84,6 +89,7 @@ module.exports = app => app.component('document', {
84
89
  this.document = doc;
85
90
  this.changes = {};
86
91
  this.editting = false;
92
+ this.shouldShowConfirmModal = false;
87
93
  },
88
94
  async remove() {
89
95
  const { doc } = await api.Model.deleteDocument({
@@ -103,4 +109,4 @@ module.exports = app => app.component('document', {
103
109
  }
104
110
  }
105
111
  }
106
- });
112
+ });
@@ -1,9 +1,3 @@
1
1
  <div class="edit-array">
2
- <div v-for="(el, i) in currentValue">
3
- <input type="text" :value="el" @input="currentValue[i] = $event.target.value; onUpdate()">
4
- <span style="cursor: pointer; color: #880000; font-weight: bold;" @click="removeValue(i)">&times;</span>
5
- </div>
6
- <div>
7
- <button @click="currentValue.push(''); onUpdate();">Add</button>
8
- </div>
2
+ <textarea ref="arrayEditor" v-model="currentValue" class="w-full border border-gray-300 p-1 h-[300px]"></textarea>
9
3
  </div>