@ditojs/admin 1.30.0 → 2.0.0

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 (78) hide show
  1. package/dist/dito-admin.es.js +5291 -6856
  2. package/dist/dito-admin.umd.js +5 -5
  3. package/dist/style.css +1 -1
  4. package/package.json +37 -22
  5. package/src/DitoAdmin.js +44 -58
  6. package/src/DitoComponent.js +18 -50
  7. package/src/DitoContext.js +7 -3
  8. package/src/TypeComponent.js +15 -13
  9. package/src/appState.js +4 -2
  10. package/src/components/DitoAccount.vue +14 -14
  11. package/src/components/DitoButtons.vue +18 -10
  12. package/src/components/DitoClipboard.vue +16 -16
  13. package/src/components/DitoContainer.vue +32 -32
  14. package/src/components/DitoCreateButton.vue +22 -23
  15. package/src/components/DitoDialog.vue +73 -18
  16. package/src/components/DitoEditButtons.vue +31 -31
  17. package/src/components/DitoElement.vue +6 -6
  18. package/src/components/DitoErrors.vue +6 -6
  19. package/src/components/DitoForm.vue +42 -43
  20. package/src/components/DitoFormNested.vue +7 -3
  21. package/src/components/DitoHeader.vue +19 -19
  22. package/src/components/DitoLabel.vue +25 -25
  23. package/src/components/DitoMenu.vue +9 -9
  24. package/src/components/DitoPagination.vue +5 -5
  25. package/src/components/DitoPane.vue +32 -32
  26. package/src/components/DitoPanel.vue +18 -18
  27. package/src/components/DitoPanels.vue +5 -3
  28. package/src/components/DitoRoot.vue +107 -30
  29. package/src/components/DitoSchema.vue +76 -74
  30. package/src/components/DitoSchemaInlined.vue +29 -29
  31. package/src/components/DitoScopes.vue +14 -13
  32. package/src/components/DitoSpinner.vue +101 -0
  33. package/src/components/DitoTableCell.vue +19 -25
  34. package/src/components/DitoTableHead.vue +10 -7
  35. package/src/components/DitoTabs.vue +7 -6
  36. package/src/components/DitoTreeItem.vue +89 -85
  37. package/src/components/DitoVNode.vue +9 -7
  38. package/src/components/DitoView.vue +25 -21
  39. package/src/mixins/DataMixin.js +2 -2
  40. package/src/mixins/DitoMixin.js +43 -46
  41. package/src/mixins/DomMixin.js +1 -1
  42. package/src/mixins/EmitterMixin.js +11 -11
  43. package/src/mixins/RouteMixin.js +20 -10
  44. package/src/mixins/SchemaParentMixin.js +2 -2
  45. package/src/mixins/SourceMixin.js +7 -9
  46. package/src/mixins/TypeMixin.js +29 -34
  47. package/src/mixins/ValidationMixin.js +4 -19
  48. package/src/types/TypeButton.vue +11 -15
  49. package/src/types/TypeCheckbox.vue +7 -8
  50. package/src/types/TypeCheckboxes.vue +14 -15
  51. package/src/types/TypeCode.vue +5 -5
  52. package/src/types/TypeColor.vue +9 -12
  53. package/src/types/TypeComponent.vue +12 -7
  54. package/src/types/TypeComputed.vue +13 -12
  55. package/src/types/TypeDate.vue +10 -11
  56. package/src/types/TypeLabel.vue +1 -1
  57. package/src/types/TypeList.vue +115 -92
  58. package/src/types/TypeMarkup.vue +166 -125
  59. package/src/types/TypeMultiselect.vue +37 -47
  60. package/src/types/TypeNumber.vue +10 -11
  61. package/src/types/TypeObject.vue +62 -46
  62. package/src/types/TypeProgress.vue +7 -8
  63. package/src/types/TypeRadio.vue +15 -14
  64. package/src/types/TypeSection.vue +10 -10
  65. package/src/types/TypeSelect.vue +32 -33
  66. package/src/types/TypeSlider.vue +20 -22
  67. package/src/types/TypeSwitch.vue +8 -9
  68. package/src/types/TypeText.vue +7 -8
  69. package/src/types/TypeTextarea.vue +8 -9
  70. package/src/types/TypeTreeList.vue +40 -34
  71. package/src/types/TypeUpload.vue +61 -61
  72. package/src/utils/accessor.js +1 -1
  73. package/src/utils/data.js +0 -4
  74. package/src/utils/options.js +48 -0
  75. package/src/utils/path.js +5 -0
  76. package/src/utils/schema.js +73 -56
  77. package/src/utils/vue.js +11 -0
  78. package/types/index.d.ts +1 -1
@@ -0,0 +1,101 @@
1
+ <template lang="pug">
2
+ .dito-spinner(
3
+ v-show="loading"
4
+ )
5
+ //- TODO: Convert to BEM
6
+ .v-pulse.v-pulse1(
7
+ :style="[spinnerStyle,spinnerDelay1]"
8
+ )
9
+ .v-pulse.v-pulse2(
10
+ :style="[spinnerStyle,spinnerDelay2]"
11
+ )
12
+ .v-pulse.v-pulse3(
13
+ :style="[spinnerStyle,spinnerDelay3]"
14
+ )
15
+ </template>
16
+
17
+ <style lang="scss">
18
+ @-webkit-keyframes v-pulseStretchDelay {
19
+ 0%,
20
+ 80%
21
+ {
22
+ transform: scale(1);
23
+ opacity: 1;
24
+ }
25
+ 45%
26
+ {
27
+ transform: scale(0.1);
28
+ opacity: 0.7;
29
+ }
30
+ }
31
+
32
+ @keyframes v-pulseStretchDelay {
33
+ 0%,
34
+ 80%
35
+ {
36
+ transform: scale(1);
37
+ opacity: 1;
38
+ }
39
+ 45%
40
+ {
41
+ transform: scale(0.1);
42
+ opacity: 0.7;
43
+ }
44
+ }
45
+ </style>
46
+
47
+ <script>
48
+ export default {
49
+ props: {
50
+ loading: {
51
+ type: Boolean,
52
+ default: true
53
+ },
54
+ color: {
55
+ type: String,
56
+ default: '#5dc596'
57
+ },
58
+ size: {
59
+ type: String,
60
+ default: '15px'
61
+ },
62
+ margin: {
63
+ type: String,
64
+ default: '2px'
65
+ },
66
+ radius: {
67
+ type: String,
68
+ default: '100%'
69
+ }
70
+ },
71
+
72
+ data() {
73
+ // TODO: Convert to using only classes
74
+ return {
75
+ spinnerStyle: {
76
+ backgroundColor: this.color,
77
+ width: this.size,
78
+ height: this.size,
79
+ margin: this.margin,
80
+ borderRadius: this.radius,
81
+ display: 'inline-block',
82
+ animationName: 'v-pulseStretchDelay',
83
+ animationDuration: '0.75s',
84
+ animationIterationCount: 'infinite',
85
+ animationTimingFunction: 'cubic-bezier(.2,.68,.18,1.08)',
86
+ animationFillMode: 'both'
87
+ },
88
+ spinnerDelay1: {
89
+ animationDelay: '0.12s'
90
+ },
91
+ spinnerDelay2: {
92
+ animationDelay: '0.24s'
93
+ },
94
+ spinnerDelay3: {
95
+ animationDelay: '0.36s'
96
+ }
97
+ }
98
+ }
99
+
100
+ }
101
+ </script>
@@ -1,24 +1,24 @@
1
1
  <template lang="pug">
2
- td(
3
- :class="cell.class"
4
- :style="cell.style"
2
+ td(
3
+ :class="cell.class"
4
+ :style="cell.style"
5
+ )
6
+ //- TODO: Implement inlined components in cell mode!
7
+ component(
8
+ v-if="cell.component"
9
+ :is="cell.component"
10
+ :schema="schema"
11
+ :dataPath="dataPath"
12
+ :data="data"
13
+ :meta="meta"
14
+ :store="store"
15
+ :nested="nested"
16
+ :disabled="disabled"
17
+ )
18
+ span(
19
+ v-else
20
+ v-html="renderCell(data)"
5
21
  )
6
- // TODO: Implement inlined components in cell mode!
7
- component(
8
- v-if="component"
9
- :is="component"
10
- :schema="schema"
11
- :dataPath="dataPath"
12
- :data="data"
13
- :meta="meta"
14
- :store="store"
15
- :nested="nested"
16
- :disabled="disabled"
17
- )
18
- span(
19
- v-else
20
- v-html="renderCell(data)"
21
- )
22
22
  </template>
23
23
 
24
24
  <script>
@@ -40,12 +40,6 @@ export default DitoComponent.component('dito-table-cell', {
40
40
  disabled: { type: Boolean, default: false }
41
41
  },
42
42
 
43
- computed: {
44
- component() {
45
- return this.resolveTypeComponent(this.cell.component)
46
- }
47
- },
48
-
49
43
  methods: {
50
44
  renderCell(item) {
51
45
  const { name, render } = this.cell
@@ -1,15 +1,18 @@
1
1
  <template lang="pug">
2
- thead.dito-table-head
3
- tr
2
+ thead.dito-table-head
3
+ tr
4
+ template(
5
+ v-for="(column, index) in columns"
6
+ )
4
7
  th(
5
- v-for="(column, index) in columns"
6
8
  v-if="shouldRender(column)"
7
9
  :class="getColumnClass(column)"
8
10
  )
9
11
  router-link(
10
12
  v-if="column.sortable"
11
13
  :to="getSortLink(column)"
12
- custom v-slot="{ navigate }"
14
+ custom
15
+ v-slot="{ navigate }"
13
16
  )
14
17
  button.dito-button(
15
18
  type="button"
@@ -21,9 +24,9 @@
21
24
  span(
22
25
  v-else
23
26
  ) {{ getLabel(column) }}
24
- th(v-if="hasEditButtons")
25
- // Empty <span> is needed for styling, see _table.sass
26
- span
27
+ th(v-if="hasEditButtons")
28
+ //- Empty <span> is needed for styling, see _table.sass
29
+ span
27
30
  </template>
28
31
 
29
32
  <style lang="sass">
@@ -1,13 +1,14 @@
1
1
  <template lang="pug">
2
- .dito-tabs
2
+ .dito-tabs
3
+ template(
4
+ v-for="(tabSchema, key) in tabs"
5
+ )
3
6
  router-link.dito-link(
4
- v-for="(tabSchema, key) in tabs"
5
7
  v-if="shouldRender(tabSchema)"
6
8
  :key="key"
7
- :to="{ hash: key }"
8
- active-class="dito-active"
9
- )
10
- | {{ getLabel(tabSchema, key) }}
9
+ :to="{ hash: `#${key}` }"
10
+ :class="{ 'dito-active': selectedTab === key }"
11
+ ) {{ getLabel(tabSchema, key) }}
11
12
  </template>
12
13
 
13
14
  <style lang="sass">
@@ -1,76 +1,76 @@
1
1
  <template lang="pug">
2
- .dito-tree-item(
3
- :id="dataPath"
4
- :class=`{
5
- 'dito-dragging': dragging,
6
- 'dito-active': active
7
- }`
8
- :style="level > 0 && { '--level': level }"
9
- )
10
- .dito-tree-header(v-if="label")
11
- .dito-tree-branch(
2
+ .dito-tree-item(
3
+ :id="dataPath"
4
+ :class=`{
5
+ 'dito-dragging': dragging,
6
+ 'dito-active': active
7
+ }`
8
+ :style="level > 0 && { '--level': level }"
9
+ )
10
+ .dito-tree-header(v-if="label")
11
+ .dito-tree-branch(
12
+ v-if="numEntries"
13
+ @click.stop="opened = !opened"
14
+ )
15
+ .dito-chevron(
12
16
  v-if="numEntries"
13
- @click.stop="opened = !opened"
17
+ :class="{ 'dito-opened': opened }"
14
18
  )
15
- .dito-chevron(
16
- v-if="numEntries"
17
- :class="{ 'dito-opened': opened }"
18
- )
19
- .dito-tree-label(v-html="label")
20
- .dito-tree-info(v-if="details") {{ details }}
21
- .dito-tree-leaf(v-else)
22
- .dito-tree-label(v-html="label")
23
- .dito-buttons.dito-buttons-small(v-if="hasEditButtons")
24
- //- Firefox doesn't like <button> here, so use <a> instead:
25
- a.dito-button(
26
- v-if="draggable"
27
- v-bind="getButtonAttributes(verbs.drag)"
28
- )
29
- button.dito-button(
30
- v-if="editable"
31
- type="button"
32
- @click="onEdit"
33
- v-bind="getButtonAttributes(verbs.edit)"
34
- )
35
- button.dito-button(
36
- v-if="deletable"
37
- type="button"
38
- @click="onDelete"
39
- v-bind="getButtonAttributes(verbs.delete)"
40
- )
41
- table.dito-properties(
42
- v-if="properties"
43
- v-show="opened"
44
- )
45
- tr(
46
- v-for="property in properties"
19
+ .dito-tree-label(v-html="label")
20
+ .dito-tree-info(v-if="details") {{ details }}
21
+ .dito-tree-leaf(v-else)
22
+ .dito-tree-label(v-html="label")
23
+ .dito-buttons.dito-buttons-small(v-if="hasEditButtons")
24
+ //- Firefox doesn't like <button> here, so use <a> instead:
25
+ a.dito-button(
26
+ v-if="draggable"
27
+ v-bind="getButtonAttributes(verbs.drag)"
28
+ )
29
+ button.dito-button(
30
+ v-if="editable"
31
+ type="button"
32
+ @click="onEdit"
33
+ v-bind="getButtonAttributes(verbs.edit)"
47
34
  )
48
- td
49
- dito-label(
50
- v-if="property.label !== false"
51
- :dataPath="getPropertyDataPath(property)"
52
- :label="getLabel(property)"
53
- )
54
- dito-table-cell(
55
- :cell="property"
56
- :schema="property"
35
+ button.dito-button(
36
+ v-if="deletable"
37
+ type="button"
38
+ @click="onDelete"
39
+ v-bind="getButtonAttributes(verbs.delete)"
40
+ )
41
+ table.dito-properties(
42
+ v-if="properties"
43
+ v-show="opened"
44
+ )
45
+ tr(
46
+ v-for="property in properties"
47
+ )
48
+ td
49
+ dito-label(
50
+ v-if="property.label !== false"
57
51
  :dataPath="getPropertyDataPath(property)"
58
- :data="data"
59
- :meta="nestedMeta"
60
- :store="store"
61
- :disabled="disabled"
52
+ :label="getLabel(property)"
62
53
  )
63
- vue-draggable(
64
- v-if="childrenSchema"
65
- v-show="opened"
66
- v-bind="getDragOptions(childrenDraggable, true)"
67
- :list="updateOrder(childrenSchema, childrenList)"
68
- @start="onStartDrag"
69
- @end="onEndDrag($event, childrenSchema)"
70
- )
54
+ dito-table-cell(
55
+ :cell="property"
56
+ :schema="property"
57
+ :dataPath="getPropertyDataPath(property)"
58
+ :data="data"
59
+ :meta="nestedMeta"
60
+ :store="store"
61
+ :disabled="disabled"
62
+ )
63
+ vue-sortable(
64
+ v-if="childrenSchema"
65
+ v-show="opened"
66
+ :list="childrenItems"
67
+ :options="getDragOptions(childrenDraggable, true)"
68
+ :itemKey="item => getItemUid(childrenSchema, item.data)"
69
+ @start="onStartDrag"
70
+ @end="onEndDrag($event, childrenSchema)"
71
+ )
72
+ template(#item="{ element: item, index }")
71
73
  dito-tree-item(
72
- v-for="(item, index) in childrenItems"
73
- :key="getItemUid(childrenSchema, item.data)"
74
74
  :schema="childrenSchema"
75
75
  :dataPath="getItemDataPath(childrenSchema, index)"
76
76
  :data="item.data"
@@ -81,8 +81,8 @@
81
81
  :label="getItemLabel(childrenSchema, item.data, { index })"
82
82
  :level="level + 1"
83
83
  )
84
- // TODO: Convert dito-tree-item to use dito-label internally, and then
85
- // pass `asObject: true` in the `getItemLabel()` call above.
84
+ //- TODO: Convert dito-tree-item to use dito-label internally, and then
85
+ //- pass `asObject: true` in the `getItemLabel()` call above.
86
86
  </template>
87
87
 
88
88
  <style lang="sass">
@@ -151,7 +151,7 @@
151
151
  </style>
152
152
 
153
153
  <script>
154
- import VueDraggable from 'vuedraggable'
154
+ import { Sortable as VueSortable } from 'sortablejs-vue3'
155
155
  import DitoComponent from '../DitoComponent.js'
156
156
  import OrderedMixin from '../mixins/OrderedMixin.js'
157
157
  import { appendDataPath } from '../utils/data.js'
@@ -160,7 +160,7 @@ import { getNamedSchemas, hasFormSchema } from '../utils/schema.js'
160
160
 
161
161
  // @vue/component
162
162
  export default DitoComponent.component('dito-tree-item', {
163
- components: { VueDraggable },
163
+ components: { VueSortable },
164
164
  mixins: [OrderedMixin],
165
165
  inject: ['container'],
166
166
 
@@ -240,28 +240,32 @@ export default DitoComponent.component('dito-tree-item', {
240
240
  },
241
241
 
242
242
  childrenItems() {
243
- const { childrenSchema } = this
244
- if (childrenSchema) {
243
+ const { childrenSchema, childrenList } = this
244
+ if (childrenSchema && childrenList) {
245
245
  const { editPath } = this.container
246
246
  const childrenOpen = !this.path && childrenSchema.open
247
247
  // Build a children list with child meta information for the template.
248
- return this.childrenList?.map((data, index) => {
249
- const path = (
250
- childrenSchema.path &&
248
+ return this.updateOrder(
249
+ childrenSchema,
250
+ childrenList.map((data, index) => {
251
+ const path = (
252
+ childrenSchema.path &&
251
253
  `${this.path}/${childrenSchema.path}/${index}`
252
- )
253
- const open = childrenOpen ||
254
+ )
255
+ const open = childrenOpen ||
254
256
  // Only count as "in edit path" when it's not the full edit path.
255
257
  editPath.startsWith(path) && path.length < editPath.length
256
- const active = editPath === path
257
- return {
258
- data,
259
- path,
260
- open,
261
- active
262
- }
263
- }) || []
258
+ const active = editPath === path
259
+ return {
260
+ data,
261
+ path,
262
+ open,
263
+ active
264
+ }
265
+ })
266
+ )
264
267
  }
268
+ return []
265
269
  },
266
270
 
267
271
  details() {
@@ -1,12 +1,14 @@
1
1
  <script>
2
2
  import DitoComponent from '../DitoComponent.js'
3
3
 
4
- // A component to simply pass through an existing vue vnode.
5
- // See: https://forum.vuejs.org/t/28162/4
6
-
7
4
  // @vue/component
8
- export default DitoComponent.component('dito-vnode', {
9
- functional: true,
10
- render: (h, context) => context.props.node
11
- })
5
+ function DitoVNode({ vnode }) {
6
+ return vnode
7
+ }
8
+
9
+ DitoVNode.props = {
10
+ vnode: { type: Object, required: true }
11
+ }
12
+
13
+ export default DitoComponent.component('dito-vnode', DitoVNode)
12
14
  </script>
@@ -1,25 +1,26 @@
1
1
  <template lang="pug">
2
- // Only render DitoView when it is active, otherwise a normal router-view
3
- // instead, to nest further route components.
4
- // NOTE: This is different from the handling in DitoForm, where `v-show` is
5
- // used to always render forms even when other nested forms are present.
6
- router-view(
7
- v-if="!isLastRoute"
8
- :key="name"
9
- )
10
- .dito-view.dito-scroll-parent(
11
- v-else-if="shouldRender(viewSchema)"
12
- :data-resource="sourceSchema.path"
13
- )
14
- dito-schema.dito-scroll(
15
- :schema="viewSchema"
16
- :data="data"
17
- :meta="meta"
18
- :store="getChildStore(name)"
19
- :disabled="isLoading"
20
- :generateLabels="false"
21
- :menuHeader="true"
2
+ template(v-if="user")
3
+ //- Only render DitoView when it is active, otherwise a normal router-view
4
+ //- instead, to nest further route components.
5
+ //- NOTE: This is different from the handling in DitoForm, where `v-show` is
6
+ //- used to always render forms even when other nested forms are present.
7
+ router-view(
8
+ v-if="!isLastRoute"
9
+ :key="name"
22
10
  )
11
+ .dito-view.dito-scroll-parent(
12
+ v-else-if="shouldRender(viewSchema)"
13
+ :data-resource="sourceSchema.path"
14
+ )
15
+ dito-schema.dito-scroll(
16
+ :schema="viewSchema"
17
+ :data="data"
18
+ :meta="meta"
19
+ :store="getChildStore(name)"
20
+ :disabled="isLoading"
21
+ :generateLabels="false"
22
+ :menuHeader="true"
23
+ )
23
24
  </template>
24
25
 
25
26
  <script>
@@ -42,7 +43,6 @@ export default DitoComponent.component('dito-view', {
42
43
 
43
44
  data() {
44
45
  return {
45
- isView: true,
46
46
  // Updated from LoadingMixin through `setLoading(isLoading)`:
47
47
  isLoading: false,
48
48
  // NOTE: Data is shared across all views because the router recycles the
@@ -60,6 +60,10 @@ export default DitoComponent.component('dito-view', {
60
60
  return this.schema.name
61
61
  },
62
62
 
63
+ isView() {
64
+ return true
65
+ },
66
+
63
67
  isSingleComponentView() {
64
68
  return isSingleComponentView(this.schema)
65
69
  },
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  isObject, isFunction, isPromise, normalizeDataPath, getValueAtDataPath
3
3
  } from '@ditojs/utils'
4
+ import { reactive } from 'vue'
4
5
  import LoadingMixin from './LoadingMixin.js'
5
6
 
6
7
  // @vue/component
@@ -25,8 +26,7 @@ export default {
25
26
  let { data = undefined, dataPath = null } = schema
26
27
  // See if there is async data loading already in process.
27
28
  const asyncEntry = (
28
- this.asyncDataEntries[name] ||
29
- this.$set(this.asyncDataEntries, name, {
29
+ this.asyncDataEntries[name] ||= reactive({
30
30
  dependencyFunction: null,
31
31
  resolveCounter: 0,
32
32
  resolvedData: null,