@ditojs/admin 2.10.5 → 2.11.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ditojs/admin",
3
- "version": "2.10.5",
3
+ "version": "2.11.0",
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,57 +33,57 @@
33
33
  "not ie_mob > 0"
34
34
  ],
35
35
  "dependencies": {
36
- "@ditojs/ui": "^2.10.5",
37
- "@ditojs/utils": "^2.10.5",
36
+ "@ditojs/ui": "^2.11.0",
37
+ "@ditojs/utils": "^2.11.0",
38
38
  "@kyvg/vue3-notification": "^2.9.1",
39
39
  "@lk77/vue3-color": "^3.0.6",
40
- "@tiptap/core": "^2.0.3",
41
- "@tiptap/extension-blockquote": "^2.0.3",
42
- "@tiptap/extension-bold": "^2.0.3",
43
- "@tiptap/extension-bullet-list": "^2.0.3",
44
- "@tiptap/extension-code": "^2.0.3",
45
- "@tiptap/extension-code-block": "^2.0.3",
46
- "@tiptap/extension-document": "^2.0.3",
47
- "@tiptap/extension-hard-break": "^2.0.3",
48
- "@tiptap/extension-heading": "^2.0.3",
49
- "@tiptap/extension-history": "^2.0.3",
50
- "@tiptap/extension-horizontal-rule": "^2.0.3",
51
- "@tiptap/extension-italic": "^2.0.3",
52
- "@tiptap/extension-link": "^2.0.3",
53
- "@tiptap/extension-list-item": "^2.0.3",
54
- "@tiptap/extension-ordered-list": "^2.0.3",
55
- "@tiptap/extension-paragraph": "^2.0.3",
56
- "@tiptap/extension-strike": "^2.0.3",
57
- "@tiptap/extension-text": "^2.0.3",
58
- "@tiptap/extension-underline": "^2.0.3",
59
- "@tiptap/pm": "^2.0.3",
60
- "@tiptap/vue-3": "^2.0.3",
40
+ "@tiptap/core": "^2.0.4",
41
+ "@tiptap/extension-blockquote": "^2.0.4",
42
+ "@tiptap/extension-bold": "^2.0.4",
43
+ "@tiptap/extension-bullet-list": "^2.0.4",
44
+ "@tiptap/extension-code": "^2.0.4",
45
+ "@tiptap/extension-code-block": "^2.0.4",
46
+ "@tiptap/extension-document": "^2.0.4",
47
+ "@tiptap/extension-hard-break": "^2.0.4",
48
+ "@tiptap/extension-heading": "^2.0.4",
49
+ "@tiptap/extension-history": "^2.0.4",
50
+ "@tiptap/extension-horizontal-rule": "^2.0.4",
51
+ "@tiptap/extension-italic": "^2.0.4",
52
+ "@tiptap/extension-link": "^2.0.4",
53
+ "@tiptap/extension-list-item": "^2.0.4",
54
+ "@tiptap/extension-ordered-list": "^2.0.4",
55
+ "@tiptap/extension-paragraph": "^2.0.4",
56
+ "@tiptap/extension-strike": "^2.0.4",
57
+ "@tiptap/extension-text": "^2.0.4",
58
+ "@tiptap/extension-underline": "^2.0.4",
59
+ "@tiptap/pm": "^2.0.4",
60
+ "@tiptap/vue-3": "^2.0.4",
61
61
  "@vueuse/integrations": "^10.2.1",
62
62
  "codeflask": "^1.4.1",
63
63
  "filesize": "^10.0.7",
64
64
  "filesize-parser": "^1.5.0",
65
- "focus-trap": "^7.4.3",
65
+ "focus-trap": "^7.5.2",
66
66
  "nanoid": "^4.0.2",
67
67
  "sortablejs": "^1.15.0",
68
68
  "tinycolor2": "^1.6.0",
69
69
  "tippy.js": "^6.3.7",
70
- "type-fest": "^3.12.0",
70
+ "type-fest": "^4.0.0",
71
71
  "vue": "^3.3.4",
72
72
  "vue-multiselect": "^3.0.0-beta.2",
73
- "vue-router": "^4.2.2",
73
+ "vue-router": "^4.2.4",
74
74
  "vue-upload-component": "^3.1.8"
75
75
  },
76
76
  "devDependencies": {
77
- "@ditojs/build": "^2.10.0",
77
+ "@ditojs/build": "^2.11.0",
78
78
  "@vitejs/plugin-vue": "^4.2.3",
79
79
  "@vue/compiler-sfc": "^3.3.4",
80
80
  "pug": "^3.0.2",
81
- "sass": "1.63.6",
81
+ "sass": "1.64.1",
82
82
  "typescript": "^5.1.6",
83
- "vite": "^4.3.9"
83
+ "vite": "^4.4.7"
84
84
  },
85
85
  "types": "types",
86
- "gitHead": "7549d96fcd1d5b9fb8e6b7d1e5573df954d9dbff",
86
+ "gitHead": "1589dbd472f04ec8a540e8b39bd7de8e2907872a",
87
87
  "scripts": {
88
88
  "build": "vite build",
89
89
  "watch": "yarn build --mode 'development' --watch",
package/src/DitoAdmin.js CHANGED
@@ -289,12 +289,12 @@ function isApiUrl(api, url) {
289
289
  }
290
290
 
291
291
  function getApiUrl(api, { url, query }) {
292
- if (!isAbsoluteUrl(url)) {
292
+ if (!url.startsWith(api.url) && !isAbsoluteUrl(url)) {
293
293
  url = combineUrls(api.url, url)
294
294
  }
295
295
  // Support optional query parameters, to be are added to the URL.
296
296
  const search = formatQuery(query)
297
- return search ? `${url}?${search}` : url
297
+ return search ? `${url}${url.includes('?') ? '&' : '?'}${search}` : url
298
298
  }
299
299
 
300
300
  function combineUrls(baseUrl, relativeUrl) {
@@ -476,7 +476,11 @@ export default DitoComponent.component('DitoForm', {
476
476
  } else if (this.isCreating) {
477
477
  // Redirect to the form editing the newly created item:
478
478
  const id = this.getItemId(this.schema, this.data)
479
- this.$router.replace({ path: resolvePath(`${this.path}/../${id}`) })
479
+ this.$router.replace({
480
+ path: resolvePath(`${this.path}/../${id}`),
481
+ // Preserve hash for tabs:
482
+ hash: this.$route.hash
483
+ })
480
484
  }
481
485
  }
482
486
  return success
@@ -57,11 +57,13 @@ slot(name="before")
57
57
  )
58
58
  template(
59
59
  v-for="(tabSchema, tab) in tabs"
60
+ :key="tab"
60
61
  )
62
+ //- TODO: Switch to v-if instead of v-show, once validation is
63
+ //- decoupled from components.
61
64
  DitoPane.dito-pane__tab(
62
- v-if="selectedTab === tab"
65
+ v-show="selectedTab === tab"
63
66
  ref="tabs"
64
- :key="tab"
65
67
  :tab="tab"
66
68
  :schema="tabSchema"
67
69
  :dataPath="dataPath"
@@ -20,10 +20,7 @@ export default {
20
20
  },
21
21
 
22
22
  methods: {
23
- handleDataSchema(schema, name, {
24
- resolveCounter = 1,
25
- ...loadingOptions
26
- } = {}) {
23
+ handleDataSchema(schema, name, loadingOptions) {
27
24
  if (!isObject(schema)) {
28
25
  schema = { data: schema }
29
26
  }
@@ -31,27 +28,24 @@ export default {
31
28
  // See if there is async data loading already in process.
32
29
  const asyncEntry = (this.asyncDataEntries[name] ||= reactive({
33
30
  dependencyFunction: null,
34
- resolveCounter: 0,
35
- resolvedData: null,
36
- resolving: false
31
+ resolvedData: undefined,
32
+ resolving: false,
33
+ resolved: false
37
34
  }))
38
35
  // If the data callback provided a dependency function when it was called,
39
36
  // cal it in every call of `handleDataSchema()` to force Vue to keep track
40
37
  // of the async dependencies.
41
38
  asyncEntry.dependencyFunction?.(this.context)
42
39
 
43
- if (asyncEntry.resolveCounter > 0) {
44
- // If the data was resolved already, return it and clear the value once
45
- // `resolveCounter` reaches zero. Counting is needed because depending
46
- // on the use of data and reactivity, multiple calls to the computed
47
- // getter are triggered when the data is changing. Clearing the resolved
48
- // data works because Vue caches the result of computed getters and only
49
- // reevaluates if one of the dependencies changed. This is to ensure
50
- // that a cached value here doesn't block / override reevaluation:
40
+ if (asyncEntry.resolved) {
41
+ // If the data was resolved already, return it and clear the resolved
42
+ // value. This works because Vue caches the result of computed getters
43
+ // and only reevaluates if one of the dependencies changed. This is to
44
+ // ensure that a cached value here doesn't block / override
45
+ // reevaluation when a dependency changes:
51
46
  const { resolvedData } = asyncEntry
52
- if (--asyncEntry.resolveCounter === 0) {
53
- asyncEntry.resolvedData = null
54
- }
47
+ asyncEntry.resolvedData = undefined
48
+ asyncEntry.resolved = false
55
49
  return resolvedData
56
50
  }
57
51
  // Avoid calling the data function twice:
@@ -73,6 +67,7 @@ export default {
73
67
  data = result
74
68
  }
75
69
  }
70
+ // NOTE: If the data is not a promise, it is resolved already.
76
71
  if (isPromise(data)) {
77
72
  // If the data is asynchronous, it can't be returned straight away.
78
73
  // But we can cheat using computed properties and `resolvedData`,
@@ -80,11 +75,16 @@ export default {
80
75
  // triggering a recompute of the computed property that calls
81
76
  // `handleDataSchema()`.
82
77
  asyncEntry.resolving = true
83
- this.resolveData(data, loadingOptions).then(data => {
84
- asyncEntry.resolveCounter = resolveCounter
85
- asyncEntry.resolvedData = data
86
- asyncEntry.resolving = false
87
- })
78
+ this.resolveData(data, loadingOptions)
79
+ .then(data => {
80
+ asyncEntry.resolvedData = data
81
+ asyncEntry.resolving = false
82
+ asyncEntry.resolved = true
83
+ })
84
+ .catch(error => {
85
+ console.error(error)
86
+ asyncEntry.resolving = false
87
+ })
88
88
  // Clear data until promise is resolved and `resolvedData` is set
89
89
  data = null
90
90
  }
@@ -322,7 +322,7 @@ export default {
322
322
  },
323
323
 
324
324
  async sendRequest({ method, url, resource, query, data, internal }) {
325
- url ||= this.getResourcePath(resource)
325
+ url ||= this.getResourceUrl(resource)
326
326
  method ||= resource?.method
327
327
  const checkUser = !internal && this.api.isApiUrl(url)
328
328
  if (checkUser) {
@@ -69,9 +69,7 @@ export default {
69
69
  },
70
70
 
71
71
  options() {
72
- const data = this.handleDataSchema(this.schema.options, 'options', {
73
- resolveCounter: 1
74
- }) ?? []
72
+ const data = this.handleDataSchema(this.schema.options, 'options') ?? []
75
73
  if (!isArray(data)) {
76
74
  throw new Error(`Invalid options data, should be array: ${data}`)
77
75
  }
@@ -31,12 +31,7 @@ export default DitoTypeComponent.register(
31
31
  get() {
32
32
  const { schema } = this
33
33
  if (schema.data || schema.dataPath) {
34
- const value = this.handleDataSchema(schema, 'schema', {
35
- // Modifying `this.data` below triggers another call of the
36
- // `value` getter, so use a value of 2 for `resolveCounter` to
37
- // return the resolved data twice.
38
- resolveCounter: 2
39
- })
34
+ const value = this.handleDataSchema(schema, 'schema')
40
35
  // TODO: Fix side-effects
41
36
  // eslint-disable-next-line
42
37
  this.data[this.name] = value