@ditojs/admin 1.12.0 → 1.13.1
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/dist/dito-admin.es.js +192 -180
- package/dist/dito-admin.umd.js +4 -4
- package/package.json +12 -7
- package/src/DitoAdmin.js +44 -20
- package/src/mixins/DitoMixin.js +5 -13
- package/src/types/TypeColor.vue +2 -0
- package/src/types/TypeMultiselect.vue +2 -2
- package/src/types/TypeSlider.vue +1 -0
- package/types/index.d.ts +1224 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.1",
|
|
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",
|
|
@@ -17,12 +17,14 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"src/",
|
|
20
|
-
"dist/"
|
|
20
|
+
"dist/",
|
|
21
|
+
"types/"
|
|
21
22
|
],
|
|
22
23
|
"scripts": {
|
|
23
24
|
"build": "vite build",
|
|
24
25
|
"watch": "yarn build --mode 'development' --watch",
|
|
25
|
-
"prepare": "yarn build"
|
|
26
|
+
"prepare": "yarn build",
|
|
27
|
+
"types": "tsc --noEmit types/index.d.ts"
|
|
26
28
|
},
|
|
27
29
|
"engines": {
|
|
28
30
|
"node": ">= 18.0.0",
|
|
@@ -35,8 +37,8 @@
|
|
|
35
37
|
"not ie_mob > 0"
|
|
36
38
|
],
|
|
37
39
|
"dependencies": {
|
|
38
|
-
"@ditojs/ui": "^1.
|
|
39
|
-
"@ditojs/utils": "^1.
|
|
40
|
+
"@ditojs/ui": "^1.13.1",
|
|
41
|
+
"@ditojs/utils": "^1.13.1",
|
|
40
42
|
"codeflask": "^1.4.1",
|
|
41
43
|
"filesize": "^10.0.5",
|
|
42
44
|
"filesize-parser": "^1.5.0",
|
|
@@ -58,11 +60,14 @@
|
|
|
58
60
|
"vuedraggable": "^2.24.3"
|
|
59
61
|
},
|
|
60
62
|
"devDependencies": {
|
|
61
|
-
"@ditojs/build": "^1.
|
|
63
|
+
"@ditojs/build": "^1.13.0",
|
|
62
64
|
"pug": "^3.0.2",
|
|
63
65
|
"sass": "1.55.0",
|
|
66
|
+
"type-fest": "^3.1.0",
|
|
67
|
+
"typescript": "^4.8.4",
|
|
64
68
|
"vite": "^3.2.2",
|
|
65
69
|
"vite-plugin-vue2": "^2.0.2"
|
|
66
70
|
},
|
|
67
|
-
"
|
|
71
|
+
"types": "types",
|
|
72
|
+
"gitHead": "0c6a508e04ca915691c1fb0f3706827c8ecfe0ab"
|
|
68
73
|
}
|
package/src/DitoAdmin.js
CHANGED
|
@@ -3,7 +3,9 @@ import VueModal from 'vue-js-modal'
|
|
|
3
3
|
import VueRouter from 'vue-router'
|
|
4
4
|
import VueNotifications from 'vue-notification'
|
|
5
5
|
import {
|
|
6
|
-
isString,
|
|
6
|
+
isString, isArray, asArray, isAbsoluteUrl,
|
|
7
|
+
merge, hyphenate, camelize,
|
|
8
|
+
defaultFormats
|
|
7
9
|
} from '@ditojs/utils'
|
|
8
10
|
import * as components from './components/index.js'
|
|
9
11
|
import * as types from './types/index.js'
|
|
@@ -39,8 +41,8 @@ export default class DitoAdmin {
|
|
|
39
41
|
api.locale ||= 'en-US'
|
|
40
42
|
api.formats = merge({}, defaultFormats, api.formats)
|
|
41
43
|
api.request ||= options => request(api, options)
|
|
42
|
-
api.getApiUrl ||=
|
|
43
|
-
api.
|
|
44
|
+
api.getApiUrl ||= options => getApiUrl(api, options)
|
|
45
|
+
api.isApiUrl ||= url => isApiUrl(api, url)
|
|
44
46
|
// Setting `api.normalizePaths = true (plural) sets both:
|
|
45
47
|
// `api.normalizePath = hyphenate` and `api.denormalizePath = camelize`
|
|
46
48
|
api.normalizePath ||= api.normalizePaths ? hyphenate : val => val
|
|
@@ -210,24 +212,16 @@ async function request(api, {
|
|
|
210
212
|
deprecate(`request.params is deprecated. Use action.method and action.path instead.`)
|
|
211
213
|
}
|
|
212
214
|
|
|
213
|
-
const
|
|
214
|
-
if (isApiRequest && !isAbsoluteUrl(url)) {
|
|
215
|
-
url = api.getApiUrl(url)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const search = query && new URLSearchParams(query).toString()
|
|
219
|
-
if (search) {
|
|
220
|
-
url = `${url}?${search}`
|
|
221
|
-
}
|
|
215
|
+
const isApiUrl = api.isApiUrl(url)
|
|
222
216
|
|
|
223
|
-
const response = await fetch(url, {
|
|
217
|
+
const response = await fetch(api.getApiUrl({ url, query }), {
|
|
224
218
|
method: method.toUpperCase(),
|
|
225
219
|
...(data && { body: JSON.stringify(data) }),
|
|
226
220
|
headers: {
|
|
227
|
-
...(
|
|
221
|
+
...(isApiUrl && api.headers),
|
|
228
222
|
...headers
|
|
229
223
|
},
|
|
230
|
-
credentials:
|
|
224
|
+
credentials: isApiUrl && api.cors?.credentials
|
|
231
225
|
? 'include'
|
|
232
226
|
: 'same-origin'
|
|
233
227
|
})
|
|
@@ -242,11 +236,41 @@ async function request(api, {
|
|
|
242
236
|
return response
|
|
243
237
|
}
|
|
244
238
|
|
|
245
|
-
function
|
|
246
|
-
|
|
247
|
-
return `${api.url.replace(/\/+$/, '')}/${path.replace(/^\/+/, '')}`
|
|
239
|
+
function isApiUrl(api, url) {
|
|
240
|
+
return !isAbsoluteUrl(url) || url.startsWith(api.url)
|
|
248
241
|
}
|
|
249
242
|
|
|
250
|
-
function
|
|
251
|
-
|
|
243
|
+
function getApiUrl(api, { url, query }) {
|
|
244
|
+
if (!isAbsoluteUrl(url)) {
|
|
245
|
+
url = combineUrls(api.url, url)
|
|
246
|
+
}
|
|
247
|
+
// Support optional query parameters, to be are added to the URL.
|
|
248
|
+
const search = formatQuery(query)
|
|
249
|
+
return search ? `${url}?${search}` : url
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function combineUrls(baseUrl, relativeUrl) {
|
|
253
|
+
// Use same approach as axios `combineURLs()` to join baseUrl & relativeUrl:
|
|
254
|
+
return `${baseUrl.replace(/\/+$/, '')}/${relativeUrl.replace(/^\/+/, '')}`
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function formatQuery(query) {
|
|
258
|
+
const entries = query
|
|
259
|
+
? isArray(query)
|
|
260
|
+
? query
|
|
261
|
+
: Object.entries(query)
|
|
262
|
+
: []
|
|
263
|
+
return new URLSearchParams(
|
|
264
|
+
// Expand array values into multiple entries under the same key, so
|
|
265
|
+
// `formatQuery({ foo: [1, 2], bar: 3 })` => 'foo=1&foo=2&bar=3'.
|
|
266
|
+
entries.reduce(
|
|
267
|
+
(entries, [key, value]) => {
|
|
268
|
+
for (const val of asArray(value)) {
|
|
269
|
+
entries.push([key, val])
|
|
270
|
+
}
|
|
271
|
+
return entries
|
|
272
|
+
},
|
|
273
|
+
[]
|
|
274
|
+
)
|
|
275
|
+
).toString()
|
|
252
276
|
}
|
package/src/mixins/DitoMixin.js
CHANGED
|
@@ -292,19 +292,14 @@ export default {
|
|
|
292
292
|
},
|
|
293
293
|
|
|
294
294
|
getResourceUrl(resource) {
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
const url = this.api.getApiUrl(path)
|
|
298
|
-
// Support optional query parameters, to be are added to the URL.
|
|
299
|
-
const { query } = resource
|
|
300
|
-
const search = query && new URLSearchParams(query).toString()
|
|
301
|
-
return search ? `${url}?${search}` : url
|
|
295
|
+
const url = this.getResourcePath(resource)
|
|
296
|
+
return url ? this.api.getApiUrl({ url, query: resource.query }) : null
|
|
302
297
|
},
|
|
303
298
|
|
|
304
299
|
async sendRequest({ method, url, resource, query, data, internal }) {
|
|
305
300
|
url ||= this.getResourcePath(resource)
|
|
306
301
|
method ||= resource?.method
|
|
307
|
-
const checkUser = !internal && this.api.
|
|
302
|
+
const checkUser = !internal && this.api.isApiUrl(url)
|
|
308
303
|
if (checkUser) {
|
|
309
304
|
await this.rootComponent.ensureUser()
|
|
310
305
|
}
|
|
@@ -385,13 +380,10 @@ export default {
|
|
|
385
380
|
if (isString(options)) {
|
|
386
381
|
options = { url: options }
|
|
387
382
|
}
|
|
388
|
-
const { url, filename } = options
|
|
389
383
|
// See: https://stackoverflow.com/a/49917066/1163708
|
|
390
384
|
const a = document.createElement('a')
|
|
391
|
-
a.href =
|
|
392
|
-
|
|
393
|
-
a.download = filename
|
|
394
|
-
}
|
|
385
|
+
a.href = this.api.getApiUrl(options)
|
|
386
|
+
a.download = options.filename ?? null
|
|
395
387
|
const { body } = document
|
|
396
388
|
body.appendChild(a)
|
|
397
389
|
a.click()
|
package/src/types/TypeColor.vue
CHANGED
|
@@ -135,11 +135,13 @@ export default TypeComponent.register('color', {
|
|
|
135
135
|
default: 'hex'
|
|
136
136
|
}),
|
|
137
137
|
|
|
138
|
+
// TODO: Rename to `showAlpha`?
|
|
138
139
|
alpha: getSchemaAccessor('alpha', {
|
|
139
140
|
type: Boolean,
|
|
140
141
|
default: false
|
|
141
142
|
}),
|
|
142
143
|
|
|
144
|
+
// TODO: Rename to `showInputs`?
|
|
143
145
|
inputs: getSchemaAccessor('inputs', {
|
|
144
146
|
type: Boolean,
|
|
145
147
|
default: true
|
|
@@ -293,8 +293,8 @@ export default TypeComponent.register('multiselect', {
|
|
|
293
293
|
placeholder() {
|
|
294
294
|
const { placeholder, searchable, taggable } = this.schema
|
|
295
295
|
return placeholder || (
|
|
296
|
-
searchable && taggable ?
|
|
297
|
-
: searchable ?
|
|
296
|
+
searchable && taggable ? `Search or add a ${this.label}`
|
|
297
|
+
: searchable ? `Select or search ${this.label}`
|
|
298
298
|
: undefined
|
|
299
299
|
)
|
|
300
300
|
}
|