@ditojs/admin 2.0.1 → 2.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ditojs/admin",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "type": "module",
5
5
  "description": "Dito.js Admin is a schema based admin interface for Dito.js Server, featuring auto-generated views and forms and built with Vue.js",
6
6
  "repository": "https://github.com/ditojs/dito/tree/master/packages/admin",
@@ -33,39 +33,38 @@
33
33
  "not ie_mob > 0"
34
34
  ],
35
35
  "dependencies": {
36
- "@ditojs/ui": "^2.0.1",
36
+ "@ditojs/ui": "^2.0.3",
37
37
  "@ditojs/utils": "^2.0.1",
38
38
  "@kyvg/vue3-notification": "^2.9.0",
39
39
  "@lk77/vue3-color": "^3.0.6",
40
- "@tiptap/core": "^2.0.1",
41
- "@tiptap/extension-blockquote": "^2.0.1",
42
- "@tiptap/extension-bold": "^2.0.1",
43
- "@tiptap/extension-bullet-list": "^2.0.1",
44
- "@tiptap/extension-code": "^2.0.1",
45
- "@tiptap/extension-code-block": "^2.0.1",
46
- "@tiptap/extension-document": "^2.0.1",
47
- "@tiptap/extension-hard-break": "^2.0.1",
48
- "@tiptap/extension-heading": "^2.0.1",
49
- "@tiptap/extension-history": "^2.0.1",
50
- "@tiptap/extension-horizontal-rule": "^2.0.1",
51
- "@tiptap/extension-italic": "^2.0.1",
52
- "@tiptap/extension-link": "^2.0.1",
53
- "@tiptap/extension-list-item": "^2.0.1",
54
- "@tiptap/extension-ordered-list": "^2.0.1",
55
- "@tiptap/extension-paragraph": "^2.0.1",
56
- "@tiptap/extension-strike": "^2.0.1",
57
- "@tiptap/extension-text": "^2.0.1",
58
- "@tiptap/extension-underline": "^2.0.1",
59
- "@tiptap/pm": "^2.0.1",
60
- "@tiptap/vue-3": "^2.0.1",
40
+ "@tiptap/core": "^2.0.2",
41
+ "@tiptap/extension-blockquote": "^2.0.2",
42
+ "@tiptap/extension-bold": "^2.0.2",
43
+ "@tiptap/extension-bullet-list": "^2.0.2",
44
+ "@tiptap/extension-code": "^2.0.2",
45
+ "@tiptap/extension-code-block": "^2.0.2",
46
+ "@tiptap/extension-document": "^2.0.2",
47
+ "@tiptap/extension-hard-break": "^2.0.2",
48
+ "@tiptap/extension-heading": "^2.0.2",
49
+ "@tiptap/extension-history": "^2.0.2",
50
+ "@tiptap/extension-horizontal-rule": "^2.0.2",
51
+ "@tiptap/extension-italic": "^2.0.2",
52
+ "@tiptap/extension-link": "^2.0.2",
53
+ "@tiptap/extension-list-item": "^2.0.2",
54
+ "@tiptap/extension-ordered-list": "^2.0.2",
55
+ "@tiptap/extension-paragraph": "^2.0.2",
56
+ "@tiptap/extension-strike": "^2.0.2",
57
+ "@tiptap/extension-text": "^2.0.2",
58
+ "@tiptap/extension-underline": "^2.0.2",
59
+ "@tiptap/pm": "^2.0.2",
60
+ "@tiptap/vue-3": "^2.0.2",
61
61
  "codeflask": "^1.4.1",
62
62
  "filesize": "^10.0.7",
63
63
  "filesize-parser": "^1.5.0",
64
64
  "nanoid": "^4.0.2",
65
- "sortablejs": "^1.15.0",
66
- "sortablejs-vue3": "^1.2.9",
67
65
  "tinycolor2": "^1.6.0",
68
66
  "vue": "^3.2.47",
67
+ "vue-draggable-plus": "^0.1.1",
69
68
  "vue-multiselect": "^3.0.0-beta.1",
70
69
  "vue-router": "^4.1.6",
71
70
  "vue-upload-component": "^3.1.8"
@@ -81,7 +80,7 @@
81
80
  "vite": "^4.2.1"
82
81
  },
83
82
  "types": "types",
84
- "gitHead": "80c209774fe4ee5243eb25d77ac9a97bfb694d8c",
83
+ "gitHead": "5ca73cc4cf410fbaa95a8e7079cb5c264cc67b7c",
85
84
  "scripts": {
86
85
  "build": "vite build",
87
86
  "watch": "yarn build --mode 'development' --watch",
@@ -52,7 +52,7 @@ component.dito-label(
52
52
  // so that buttons always appear right-aligned:
53
53
  flex: 1 1 auto
54
54
  &::after
55
- content: '\a0' // &nbps;
55
+ content: '\a0' //  
56
56
 
57
57
  .dito-label-prefix,
58
58
  .dito-label-suffix
@@ -94,8 +94,9 @@ component.dito-label(
94
94
  > .dito-schema-content
95
95
  > .dito-pane
96
96
  > .dito-container
97
- > .dito-label:not(.dito-label-component)
98
- display: inline-block
97
+ display: flex
98
+ flex-flow: row wrap
99
+ align-items: baseline
99
100
  </style>
100
101
 
101
102
  <script>
@@ -130,11 +131,7 @@ export default DitoComponent.component('dito-label', {
130
131
  },
131
132
 
132
133
  attributes() {
133
- return {
134
- ...(this.collapsible && {
135
- onClick: this.onClick
136
- })
137
- }
134
+ return this.collapsible ? { onClick: this.onClick } : {}
138
135
  },
139
136
 
140
137
  isActive() {
@@ -60,29 +60,30 @@
60
60
  :store="store"
61
61
  :disabled="disabled"
62
62
  )
63
- vue-sortable(
63
+ vue-draggable(
64
64
  v-if="childrenSchema"
65
65
  v-show="opened"
66
- :list="childrenItems"
67
- :options="getDragOptions(childrenDraggable, true)"
68
- :itemKey="item => getItemUid(childrenSchema, item.data)"
66
+ :modelValue="updateOrder(childrenSchema, childrenList)"
67
+ @update:modelValue="value => childrenList = value"
69
68
  @start="onStartDrag"
70
69
  @end="onEndDrag($event, childrenSchema)"
70
+ v-bind="getDragOptions(childrenDraggable, true)"
71
71
  )
72
- template(#item="{ element: item, index }")
73
- dito-tree-item(
74
- :schema="childrenSchema"
75
- :dataPath="getItemDataPath(childrenSchema, index)"
76
- :data="item.data"
77
- :path="item.path"
78
- :open="item.open"
79
- :active="item.active"
80
- :draggable="childrenDraggable"
81
- :label="getItemLabel(childrenSchema, item.data, { index })"
82
- :level="level + 1"
83
- )
84
- //- TODO: Convert dito-tree-item to use dito-label internally, and then
85
- //- pass `asObject: true` in the `getItemLabel()` call above.
72
+ dito-tree-item(
73
+ v-for="(item, index) in childrenItems"
74
+ :key="getItemUid(childrenSchema, item.data)"
75
+ :schema="childrenSchema"
76
+ :dataPath="getItemDataPath(childrenSchema, index)"
77
+ :data="item.data"
78
+ :path="item.path"
79
+ :open="item.open"
80
+ :active="item.active"
81
+ :draggable="childrenDraggable"
82
+ :label="getItemLabel(childrenSchema, item.data, { index })"
83
+ :level="level + 1"
84
+ )
85
+ //- TODO: Convert dito-tree-item to use dito-label internally, and then
86
+ //- pass `asObject: true` in the `getItemLabel()` call above.
86
87
  </template>
87
88
 
88
89
  <style lang="sass">
@@ -151,7 +152,7 @@
151
152
  </style>
152
153
 
153
154
  <script>
154
- import { Sortable as VueSortable } from 'sortablejs-vue3'
155
+ import { VueDraggable } from 'vue-draggable-plus'
155
156
  import DitoComponent from '../DitoComponent.js'
156
157
  import OrderedMixin from '../mixins/OrderedMixin.js'
157
158
  import { appendDataPath } from '../utils/data.js'
@@ -160,7 +161,7 @@ import { getNamedSchemas, hasFormSchema } from '../utils/schema.js'
160
161
 
161
162
  // @vue/component
162
163
  export default DitoComponent.component('dito-tree-item', {
163
- components: { VueSortable },
164
+ components: { VueDraggable },
164
165
  mixins: [OrderedMixin],
165
166
  inject: ['container'],
166
167
 
@@ -3,7 +3,7 @@ import ValidationMixin from './ValidationMixin.js'
3
3
  import { getSchemaAccessor } from '../utils/accessor.js'
4
4
  import { computeValue } from '../utils/schema.js'
5
5
  import { getItem, getParentItem } from '../utils/data.js'
6
- import { isString, asArray, camelize } from '@ditojs/utils'
6
+ import { isString, asArray } from '@ditojs/utils'
7
7
 
8
8
  // @vue/component
9
9
  export default {
@@ -156,10 +156,17 @@ export default {
156
156
  type: String
157
157
  }),
158
158
 
159
+ // @overridable
160
+ events() {
161
+ const { onFocus, onBlur, onInput, onChange } = this
162
+ return { onFocus, onBlur, onInput, onChange }
163
+ },
164
+
159
165
  attributes() {
160
166
  const { nativeField, textField } = this.$options
161
167
 
162
168
  const attributes = {
169
+ ...this.events,
163
170
  disabled: this.disabled
164
171
  }
165
172
 
@@ -176,25 +183,7 @@ export default {
176
183
  }
177
184
  }
178
185
 
179
- return {
180
- ...Object.fromEntries(
181
- Object.entries(this.$attrs).filter(([key]) => key.startsWith('on'))
182
- ),
183
- ...this.events,
184
- ...attributes
185
- }
186
- },
187
-
188
- events() {
189
- const events = this.getEvents()
190
- // Register callbacks for all provides non-recognized events,
191
- // assuming they are native events.
192
- // TODO: Move to vue3-style `on[A-Z]` event handlers naming that aren't
193
- // namespaced in `schema.events` once the transition is complete.
194
- for (const event of Object.keys(this.schema.events || {})) {
195
- events[`on${camelize(event, true)}`] ||= () => this.emitEvent(event)
196
- }
197
- return events
186
+ return attributes
198
187
  },
199
188
 
200
189
  validations() {
@@ -235,12 +224,6 @@ export default {
235
224
  }
236
225
  },
237
226
 
238
- // @overridable
239
- getEvents() {
240
- const { onFocus, onBlur, onInput, onChange } = this
241
- return { onFocus, onBlur, onInput, onChange }
242
- },
243
-
244
227
  // @overridable
245
228
  getValidations() {
246
229
  return null
@@ -41,16 +41,17 @@ export default TypeComponent.register([
41
41
  closeForm: getSchemaAccessor('closeForm', {
42
42
  type: Boolean,
43
43
  default: false
44
- })
45
- },
44
+ }),
46
45
 
47
- methods: {
48
46
  // @override
49
- getEvents() {
47
+ events() {
50
48
  const { onFocus, onBlur, onClick } = this
51
49
  return { onFocus, onBlur, onClick }
52
- },
50
+ }
51
+
52
+ },
53
53
 
54
+ methods: {
54
55
  async submit(options) {
55
56
  return this.resourceComponent?.submit(this, options)
56
57
  },
@@ -38,86 +38,87 @@
38
38
  :columns="columns"
39
39
  :hasEditButtons="hasEditButtons"
40
40
  )
41
- vue-sortable(
41
+ vue-draggable(
42
42
  tag="tbody"
43
- :list="updateOrder(sourceSchema, listData, paginationRange)"
44
- :options="getDragOptions(draggable)"
45
- :itemKey="item => getItemUid(schema, item)"
43
+ :modelValue="updateOrder(sourceSchema, listData, paginationRange)"
44
+ @update:modelValue="value => listData = value"
46
45
  @start="onStartDrag"
47
46
  @end="onEndDrag"
47
+ :v-bind="getDragOptions(draggable)"
48
48
  )
49
- template(#item="{ element: item, index }")
50
- tr(
51
- :id="getDataPath(index)"
52
- )
53
- template(v-if="columns")
54
- template(
55
- v-for="column in columns"
56
- )
57
- dito-table-cell(
58
- v-if="shouldRender(column)"
59
- :key="column.name"
60
- :class="getCellClass(column)"
61
- :cell="column"
62
- :schema="schema"
63
- :dataPath="getDataPath(index)"
64
- :data="item"
65
- :meta="nestedMeta"
66
- :store="store"
67
- :nested="false"
68
- :disabled="disabled || isLoading"
69
- )
49
+ tr(
50
+ v-for="item, index in listData"
51
+ :key="getItemUid(schema, item)"
52
+ :id="getDataPath(index)"
53
+ )
54
+ template(v-if="columns")
70
55
  template(
71
- v-else
72
- )
73
- td
74
- dito-schema-inlined(
75
- v-if="isInlined"
76
- :label="getItemLabel(schema, item, { index, asObject: true })"
77
- :schema="getItemFormSchema(schema, item, context)"
78
- :dataPath="getDataPath(index)"
79
- :data="item"
80
- :meta="nestedMeta"
81
- :store="getChildStore(index)"
82
- :disabled="disabled || isLoading"
83
- :collapsed="collapsed"
84
- :collapsible="collapsible"
85
- :deletable="deletable"
86
- :draggable="draggable"
87
- :editable="editable"
88
- :editPath="getEditPath(item, index)"
89
- @delete="deleteItem(item, index)"
90
- )
91
- component(
92
- v-else-if="schema.component"
93
- :is="schema.component"
94
- :dataPath="getDataPath(index)"
95
- :data="item"
96
- :nested="false"
97
- )
98
- span(
99
- v-else-if="render"
100
- v-html="render(getContext(item, index))"
101
- )
102
- span(
103
- v-else
104
- v-html="getItemLabel(schema, item, { index })"
105
- )
106
- td.dito-cell-edit-buttons(
107
- v-if="hasCellEditButtons"
56
+ v-for="column in columns"
108
57
  )
109
- dito-edit-buttons(
110
- :deletable="deletable"
111
- :draggable="draggable"
112
- :editable="editable"
113
- :editPath="getEditPath(item, index)"
58
+ dito-table-cell(
59
+ v-if="shouldRender(column)"
60
+ :key="column.name"
61
+ :class="getCellClass(column)"
62
+ :cell="column"
63
+ :schema="schema"
64
+ :dataPath="getDataPath(index)"
65
+ :data="item"
66
+ :meta="nestedMeta"
67
+ :store="store"
68
+ :nested="false"
69
+ :disabled="disabled || isLoading"
70
+ )
71
+ template(
72
+ v-else
73
+ )
74
+ td
75
+ dito-schema-inlined(
76
+ v-if="isInlined"
77
+ :label="getItemLabel(schema, item, { index, asObject: true })"
114
78
  :schema="getItemFormSchema(schema, item, context)"
115
79
  :dataPath="getDataPath(index)"
116
80
  :data="item"
117
81
  :meta="nestedMeta"
118
82
  :store="getChildStore(index)"
83
+ :disabled="disabled || isLoading"
84
+ :collapsed="collapsed"
85
+ :collapsible="collapsible"
86
+ :deletable="deletable"
87
+ :draggable="draggable"
88
+ :editable="editable"
89
+ :editPath="getEditPath(item, index)"
119
90
  @delete="deleteItem(item, index)"
120
91
  )
92
+ component(
93
+ v-else-if="schema.component"
94
+ :is="schema.component"
95
+ :dataPath="getDataPath(index)"
96
+ :data="item"
97
+ :nested="false"
98
+ )
99
+ span(
100
+ v-else-if="render"
101
+ v-html="render(getContext(item, index))"
102
+ )
103
+ span(
104
+ v-else
105
+ v-html="getItemLabel(schema, item, { index })"
106
+ )
107
+ td.dito-cell-edit-buttons(
108
+ v-if="hasCellEditButtons"
109
+ )
110
+ dito-edit-buttons(
111
+ :deletable="deletable"
112
+ :draggable="draggable"
113
+ :editable="editable"
114
+ :editPath="getEditPath(item, index)"
115
+ :schema="getItemFormSchema(schema, item, context)"
116
+ :dataPath="getDataPath(index)"
117
+ :data="item"
118
+ :meta="nestedMeta"
119
+ :store="getChildStore(index)"
120
+ @delete="deleteItem(item, index)"
121
+ )
121
122
  //- Render create buttons inside table when not in a single component view:
122
123
  tfoot(
123
124
  v-if="hasListButtons && !single"
@@ -175,11 +176,11 @@
175
176
  </style>
176
177
 
177
178
  <script>
179
+ import { VueDraggable } from 'vue-draggable-plus'
178
180
  import TypeComponent from '../TypeComponent.js'
179
181
  import DitoContext from '../DitoContext.js'
180
182
  import SourceMixin from '../mixins/SourceMixin.js'
181
183
  import OrderedMixin from '../mixins/OrderedMixin.js'
182
- import { Sortable as VueSortable } from 'sortablejs-vue3'
183
184
  import {
184
185
  getNamedSchemas, getViewEditPath,
185
186
  resolveSchemaComponent, resolveSchemaComponents
@@ -190,7 +191,7 @@ import { pickBy, equals, hyphenate } from '@ditojs/utils'
190
191
 
191
192
  // @vue/component
192
193
  export default TypeComponent.register('list', {
193
- components: { VueSortable },
194
+ components: { VueDraggable },
194
195
  mixins: [SourceMixin, OrderedMixin],
195
196
 
196
197
  getSourceType(type) {
@@ -7,8 +7,6 @@
7
7
  )
8
8
  vue-multiselect(
9
9
  ref="element"
10
- v-model="selectedOptions"
11
- v-bind="attributes"
12
10
  :show-labels="false"
13
11
  :placeholder="placeholder"
14
12
  tag-placeholder="Press enter to add new tag",
@@ -25,9 +23,12 @@
25
23
  :clear-on-select="!searchFilter"
26
24
  :close-on-select="!stayOpen"
27
25
  :loading="isLoading"
28
- @open="populate = true"
26
+ @open="onOpen"
27
+ @close="onClose"
29
28
  @tag="onAddTag"
30
29
  @search-change="onSearchChange"
30
+ v-model="selectedOptions"
31
+ v-bind="attributes"
31
32
  )
32
33
  button.dito-button-clear.dito-button-overlay(
33
34
  type="button"
@@ -224,6 +225,7 @@
224
225
  <script>
225
226
  import TypeComponent from '../TypeComponent.js'
226
227
  import DitoContext from '../DitoContext.js'
228
+ import TypeMixin from '../mixins/TypeMixin.js'
227
229
  import OptionsMixin from '../mixins/OptionsMixin.js'
228
230
  import VueMultiselect from 'vue-multiselect'
229
231
  import { getSchemaAccessor } from '../utils/accessor.js'
@@ -329,6 +331,24 @@ export default TypeComponent.register('multiselect', {
329
331
  this.$refs.element.activate()
330
332
  },
331
333
 
334
+ onOpen() {
335
+ this.populate = true
336
+ },
337
+
338
+ onClose() {
339
+ // Since we don't fire blur events while the multiselect is open (see
340
+ // below), we need to do it here, when it's actually closed.
341
+ if (this.focused) {
342
+ this.onBlur()
343
+ }
344
+ },
345
+
346
+ onBlur() {
347
+ if (!this.$refs.element.isOpen) {
348
+ TypeMixin.methods.onBlur.call(this)
349
+ }
350
+ },
351
+
332
352
  onAddTag(tag) {
333
353
  const option = this.addTagOption(tag)
334
354
  if (option) {
@@ -2,7 +2,6 @@
2
2
  switch-button.dito-switch(
3
3
  ref="element"
4
4
  :id="dataPath"
5
- :sync="true"
6
5
  :labels="labels"
7
6
  v-model="value"
8
7
  v-bind="attributes"
@@ -12,41 +12,42 @@
12
12
  span Status
13
13
  th
14
14
  span
15
- vue-sortable(
15
+ vue-draggable(
16
16
  tag="tbody"
17
- :list="files"
18
- :options="getDragOptions(draggable)"
19
- itemKey="key"
20
17
  @start="onStartDrag"
21
18
  @end="onEndDrag"
19
+ v-model="files"
20
+ v-bind="getDragOptions(draggable)"
22
21
  )
23
- template(#item="{ element: file, index }")
24
- tr
25
- td(v-html="renderFile(file, index)")
26
- td {{ formatFileSize(file.size) }}
27
- td
28
- template(v-if="file.upload")
29
- template(v-if="file.upload.error")
30
- | Error: {{ file.upload.error }}
31
- template(v-else-if="file.upload.active")
32
- | Uploading...
33
- template(v-else-if="file.upload.success")
34
- | Uploaded
35
- template(v-else)
36
- | Stored
37
- td.dito-cell-edit-buttons
38
- .dito-buttons.dito-buttons-round
39
- //- Firefox doesn't like <button> here, so use <a> instead:
40
- a.dito-button(
41
- v-if="draggable"
42
- v-bind="getButtonAttributes(verbs.drag)"
43
- )
44
- button.dito-button(
45
- v-if="deletable"
46
- type="button"
47
- @click="deleteFile(file, index)"
48
- v-bind="getButtonAttributes(verbs.delete)"
49
- )
22
+ tr(
23
+ v-for="(file, index) in files"
24
+ :key="file.key"
25
+ )
26
+ td(v-html="renderFile(file, index)")
27
+ td {{ formatFileSize(file.size) }}
28
+ td
29
+ template(v-if="file.upload")
30
+ template(v-if="file.upload.error")
31
+ | Error: {{ file.upload.error }}
32
+ template(v-else-if="file.upload.active")
33
+ | Uploading...
34
+ template(v-else-if="file.upload.success")
35
+ | Uploaded
36
+ template(v-else)
37
+ | Stored
38
+ td.dito-cell-edit-buttons
39
+ .dito-buttons.dito-buttons-round
40
+ //- Firefox doesn't like <button> here, so use <a> instead:
41
+ a.dito-button(
42
+ v-if="draggable"
43
+ v-bind="getButtonAttributes(verbs.drag)"
44
+ )
45
+ button.dito-button(
46
+ v-if="deletable"
47
+ type="button"
48
+ @click="deleteFile(file, index)"
49
+ v-bind="getButtonAttributes(verbs.delete)"
50
+ )
50
51
  tfoot
51
52
  tr
52
53
  td(:colspan="4")
@@ -106,11 +107,11 @@
106
107
  </style>
107
108
 
108
109
  <script>
110
+ import VueUpload from 'vue-upload-component'
111
+ import { VueDraggable } from 'vue-draggable-plus'
109
112
  import TypeComponent from '../TypeComponent.js'
110
113
  import DitoContext from '../DitoContext.js'
111
114
  import OrderedMixin from '../mixins/OrderedMixin.js'
112
- import VueUpload from 'vue-upload-component'
113
- import { Sortable as VueSortable } from 'sortablejs-vue3'
114
115
  import parseFileSize from 'filesize-parser'
115
116
  import { getSchemaAccessor } from '../utils/accessor.js'
116
117
  import { formatFileSize } from '../utils/units.js'
@@ -119,7 +120,7 @@ import { isArray, asArray, escapeHtml } from '@ditojs/utils'
119
120
 
120
121
  // @vue/component
121
122
  export default TypeComponent.register('upload', {
122
- components: { VueUpload, VueSortable },
123
+ components: { VueUpload, VueDraggable },
123
124
  mixins: [OrderedMixin],
124
125
 
125
126
  data() {