@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.
@@ -0,0 +1,1224 @@
1
+ // Type definitions for Dito.js admin
2
+ // Project: <https://github.com/ditojs/dito/>
3
+
4
+ import {
5
+ DateFormat,
6
+ format as utilsFormat,
7
+ NumberFormat,
8
+ TimeFormat
9
+ } from '@ditojs/utils'
10
+ import { RequireAtLeastOne, SetOptional } from 'type-fest'
11
+ import Vue, { VueConstructor } from 'vue'
12
+
13
+ declare global {
14
+ const dito: DitoGlobal
15
+ }
16
+
17
+ export default DitoAdmin
18
+ export interface DitoGlobal {
19
+ api?: ApiConfig
20
+ base?: string
21
+ settings?: Record<string, any>
22
+ }
23
+ export type RequestMethod = <T>({
24
+ url,
25
+ method,
26
+ data,
27
+ query,
28
+ params,
29
+ headers
30
+ }: {
31
+ url: string
32
+ /**
33
+ * @default 'get'
34
+ */
35
+ method: HTTPVerb
36
+ data: any
37
+ /** @deprecated use query instead */
38
+ params: ConstructorParameters<typeof URLSearchParams>[0]
39
+ query: ConstructorParameters<typeof URLSearchParams>[0]
40
+ headers: Record<string, string>
41
+ }) => Promise<RequestMethodResponse<T>>
42
+
43
+ export type RequestMethodResponse<T> = Response & { data: T }
44
+
45
+ export interface ApiResource {
46
+ type: string
47
+ path?: string
48
+ parent?: ApiResource
49
+ }
50
+
51
+ export interface ApiConfig {
52
+ /**
53
+ * The base url to use for api requests.
54
+ */
55
+ url?: string
56
+ /**
57
+ * @defaultValue 'en-US'
58
+ */
59
+ locale?: string
60
+ formats?: {
61
+ number?: NumberFormat
62
+ date?: DateFormat
63
+ time?: TimeFormat
64
+ }
65
+ request?: RequestMethod
66
+ /**
67
+ * Whether to display admin notifications.
68
+ *
69
+ * @default `true`
70
+ */
71
+ notifications?:
72
+ | boolean
73
+ | {
74
+ /**
75
+ * The amount of milliseconds multiplied with the amount of characters
76
+ * displayed in the notification, plus 40 (40 + title + message).
77
+ * @defaultValue `20`
78
+ */
79
+ durationFactor: number
80
+ }
81
+ cors?: {
82
+ /**
83
+ * Whether cross-site `Access-Control` requests are made using credentials.
84
+ */
85
+ credentials: boolean
86
+ }
87
+ /**
88
+ * Setting normalizePaths to `true` sets `api.normalizePath` to hyphenate
89
+ * camelized strings and `api.denormalizePath` to do the opposite.
90
+ *
91
+ * @default Defaults to Application.config.app.normalizePaths and then
92
+ * `false` when missing.
93
+ */
94
+ normalizePaths?: boolean
95
+ /**
96
+ * @default When `api.normalizePaths = true` (plural),
97
+ * `require('@ditojs/utils').hyphenate` is used for path normalization.
98
+ * Otherwise paths are left unchanged.
99
+ */
100
+ normalizePath?: (path: string) => string
101
+ /**
102
+ * @default When `api.normalizePaths = true` (plural),
103
+ * `require('@ditojs/utils').camelize` is used for path denormalization.
104
+ * Otherwise paths are left unchanged.
105
+ */
106
+ denormalizePath?: (path: string) => string
107
+ /**
108
+ * Auth resources
109
+ */
110
+ users?: {
111
+ path: string
112
+ login?: {
113
+ /**
114
+ * @defaultValue `'login'`
115
+ */
116
+ path?: string
117
+ /**
118
+ * @defaultValue `'post'`
119
+ */
120
+ method?: HTTPVerb
121
+ }
122
+ logout?: {
123
+ /**
124
+ * @defaultValue `'logout'`
125
+ */
126
+ path?: string
127
+ /**
128
+ * @defaultValue `'post'`
129
+ */
130
+ method?: HTTPVerb
131
+ }
132
+ session?: {
133
+ /**
134
+ * @defaultValue `'session'`
135
+ */
136
+ path?: string
137
+ /**
138
+ * @defaultValue `'get'`
139
+ */
140
+ method?: HTTPVerb
141
+ }
142
+ }
143
+ /**
144
+ * Optionally override resource path handlers.
145
+ */
146
+ resources?: Record<string, (resource: ApiResource | string) => string>
147
+
148
+ /**
149
+ * Optionally override / extend headers
150
+ * @defaultValue `{
151
+ * 'Content-Type': 'application/json'
152
+ * }`
153
+ */
154
+ headers?: Record<string, string>
155
+
156
+ /**
157
+ * Configures how urls passed to `DitoAdmin.request` are checked to see if
158
+ * they are an API request.
159
+ *
160
+ * By default (if `api.request` is not overridden) API requests include
161
+ * `api.url` as their base url, `api.headers` in their headers. If
162
+ * `api.cors.credentials` is set to `true`, cross-site `Access-Control`
163
+ * requests are made using credentials.
164
+ */
165
+ isApiRequest?: (url: string) => boolean
166
+ }
167
+
168
+ export interface BaseSchema<$Item>
169
+ extends SchemaDitoMixin<$Item>,
170
+ SchemaTypeMixin<$Item> {
171
+ default?: OrItemAccessor<$Item>
172
+ compute?: ItemAccessor<$Item>
173
+ data?: OrItemAccessor<$Item, {}, Record<string, any>>
174
+ omitPadding?: boolean
175
+ break?: 'before' | 'after'
176
+ }
177
+
178
+ // TODO: finish off DitoMixin docs
179
+ // (methods / computed / watch / events / `on[A-Z]`-style callbacks)
180
+ export interface SchemaDitoMixin<$Item> {
181
+ /**
182
+ * Only displays the component if the schema accessor returns `true`
183
+ */
184
+ if?: OrItemAccessor<$Item, {}, boolean>
185
+
186
+ /**
187
+ * Specifies validations rules to add, remove (by setting to `undefined`) or
188
+ * change before value validation occurs. Rule changes do not influence how
189
+ * the component is rendered.
190
+ */
191
+ rules?: {
192
+ required?: boolean
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Return false to mark event as handled and stop it from propagating to parent
198
+ * schemas.
199
+ */
200
+ export type ItemEventHandler<$Item = any> = (
201
+ itemParams: DitoContext<$Item>
202
+ ) => void | false
203
+
204
+ export interface SchemaTypeMixin<$Item> {
205
+ /**
206
+ * The label of the component.
207
+ *
208
+ * @defaultValue The title-cased component name.
209
+ */
210
+ label?: OrItemAccessor<$Item, {}, string | boolean>
211
+
212
+ /**
213
+ * The width of the component. The value can either be given in percent
214
+ * (e.g. '20%' or a value between 0 and 1), or as 'auto' to have the width
215
+ * depend on its contents or as 'fill' to fill left over space. A line will
216
+ * contain multiple components until their widths exceed 100%.
217
+ */
218
+ width?: OrItemAccessor<
219
+ $Item,
220
+ {},
221
+ 'auto' | 'fill' | `${number}%` | `${number}/${number}` | number
222
+ >
223
+
224
+ /**
225
+ * Whether the component is visible.
226
+ *
227
+ * @defaultValue `true`
228
+ */
229
+ visible?: OrItemAccessor<$Item, {}, boolean>
230
+
231
+ /**
232
+ * @defaultValue `false`
233
+ */
234
+ // TODO: document exclude
235
+ exclude?: OrItemAccessor<$Item, {}, boolean>
236
+
237
+ /**
238
+ * Whether the field is required.
239
+ * @defaultValue `false`
240
+ */
241
+ required?: OrItemAccessor<$Item, {}, boolean>
242
+
243
+ /**
244
+ * Whether the value is read only.
245
+ *
246
+ * @defaultValue `false`
247
+ */
248
+ readonly?: OrItemAccessor<$Item, {}, boolean>
249
+
250
+ /**
251
+ * Whether to autofocus the field.
252
+ * @defaultValue `false`
253
+ */
254
+ autofocus?: OrItemAccessor<$Item, {}, boolean>
255
+
256
+ /**
257
+ * Whether the field can be cleared.
258
+ * @defaultValue `false`
259
+ */
260
+ clearable?: OrItemAccessor<$Item, {}, boolean>
261
+
262
+ /**
263
+ * Specifies a short hint intended to aid the user with data entry when the
264
+ * input has no value.
265
+ */
266
+ placeholder?: OrItemAccessor<$Item, {}, any>
267
+
268
+ /**
269
+ * Whether the input field should have autocomplete enabled.
270
+ */
271
+ autocomplete?: OrItemAccessor<$Item, {}, 'on' | 'off'>
272
+
273
+ /**
274
+ * Specifies a function which changes the item value into another format,
275
+ * before it is passed to the component.
276
+ */
277
+ format?: ItemAccessor<$Item, {}, any>
278
+ disabled?: OrItemAccessor<$Item, {}, boolean>
279
+
280
+ /**
281
+ * Specifies a function which parses the component value when it changes,
282
+ *
283
+ */
284
+ parse?: ItemAccessor<$Item, any>
285
+
286
+ // TODO: document process
287
+ process?: OrItemAccessor<$Item>
288
+
289
+ // TODO: document name
290
+ name?: string
291
+
292
+ onFocus?: ItemEventHandler<$Item>
293
+ onBlur?: ItemEventHandler<$Item>
294
+ onChange?: ItemEventHandler<$Item>
295
+ onInput?: ItemEventHandler<$Item>
296
+ events?: {
297
+ focus?: ItemEventHandler<$Item>
298
+ blur?: ItemEventHandler<$Item>
299
+ change?: ItemEventHandler<$Item>
300
+ input?: ItemEventHandler<$Item>
301
+ }
302
+ }
303
+
304
+ export interface SchemaSourceMixin<$Item> {
305
+ /**
306
+ * The number of items displayed per page. When not provided, all items are
307
+ * rendered.
308
+ *
309
+ * @defaultValue `false`
310
+ */
311
+ paginate?: OrItemAccessor<$Item, {}, number>
312
+ // TODO: document inlined
313
+ /**
314
+ * @defaultValue `false`
315
+ */
316
+ inlined?: OrItemAccessor<$Item, {}, boolean>
317
+ /**
318
+ * Whether to add a button to create list items.
319
+ *
320
+ * @defaultValue `false`
321
+ */
322
+ creatable?: OrItemAccessor<
323
+ $Item,
324
+ {},
325
+ | boolean
326
+ | {
327
+ label: string
328
+ }
329
+ >
330
+ /**
331
+ * Whether to add edit buttons next to the list items.
332
+ *
333
+ * @defaultValue `false`
334
+ */
335
+ editable?: OrItemAccessor<
336
+ $Item,
337
+ {},
338
+ | boolean
339
+ | {
340
+ label: string
341
+ }
342
+ >
343
+ /**
344
+ * Whether to add delete buttons next to the list items.
345
+ *
346
+ * @defaultValue `false`
347
+ */
348
+ deletable?: OrItemAccessor<
349
+ $Item,
350
+ {},
351
+ | boolean
352
+ | {
353
+ label: string
354
+ }
355
+ >
356
+ /**
357
+ * The column used for the order resulting from dragging around list entries
358
+ * when the `draggable` property of the list schema is set to `true`.
359
+ */
360
+ orderKey?: string
361
+ /**
362
+ * Whether the items can be reordered by the user. Set the `orderKey` property
363
+ * if you want the order to be persisted into a column.
364
+ * @defaultValue `false`
365
+ */
366
+ draggable?: OrItemAccessor<$Item, {}, boolean>
367
+ /**
368
+ * Whether an inlined form is collapsible.
369
+ * @defaultValue `null`
370
+ */
371
+ collapsible?: OrItemAccessor<$Item, {}, boolean | null>
372
+ /**
373
+ * Whether an inlined form is collapsed.
374
+ */
375
+ collapsed?: OrItemAccessor<$Item, {}, boolean>
376
+ resource?: Resource
377
+ }
378
+
379
+ export type SchemaOptionsOption<$Value> =
380
+ | { label: string; value: $Value }
381
+ | $Value
382
+ export type SchemaOptions<$Item, $Option = any> =
383
+ | SchemaOptionsOption<$Option[]>
384
+ | {
385
+ /**
386
+ * The function which is called to load the options.
387
+ */
388
+ data?: OrItemAccessor<
389
+ $Item,
390
+ {},
391
+ OrItemAccessor<$Item, {}, OrPromiseOf<SchemaOptionsOption<$Option>[]>>
392
+ >
393
+ /**
394
+ * Either the key of the option property which should be treated as
395
+ * the option label or a function returning the option label.
396
+ *
397
+ * @defaultValue `'label'` when no label is supplied and the options are
398
+ * objects
399
+ */
400
+ label?: keyof $Option | ItemAccessor<$Item, { option: $Option }, string>
401
+ /**
402
+ * Either the key of the option property which should be treated as
403
+ * the value or a function returning the option value.
404
+ *
405
+ * @defaultValue `'value'` when no label is supplied and the options are
406
+ * objects
407
+ */
408
+ // TODO: when relate is set, the default value is 'id'
409
+ value?: keyof $Option | ItemAccessor<$Item, { option: $Option }>
410
+ /**
411
+ * The key of the option property which should used to group the options.
412
+ */
413
+ groupBy?: keyof $Option
414
+ }
415
+
416
+ export interface SchemaOptionsMixin<$Item, $Option = any> {
417
+ options?: SchemaOptions<$Item, $Option>
418
+ relate?: boolean
419
+ }
420
+
421
+ export interface SchemaNumberMixin<$Item> {
422
+ /**
423
+ * The minimum value.
424
+ */
425
+ min?: OrItemAccessor<$Item, {}, number>
426
+
427
+ /**
428
+ * The maximum value.
429
+ */
430
+ max?: OrItemAccessor<$Item, {}, number>
431
+
432
+ /**
433
+ * The minimum and maximum value.
434
+ */
435
+ range?: OrItemAccessor<$Item, {}, [number, number]>
436
+ /**
437
+ * When defined, buttons with up and down arrows are added next to the input
438
+ * field. Which when pressed will add or subtract `step` from the value.
439
+ */
440
+ step?: OrItemAccessor<$Item, {}, number>
441
+ /**
442
+ * The amount of decimals to round to.
443
+ */
444
+ decimals?: OrItemAccessor<$Item, {}, number>
445
+ rules?: Omit<SchemaNumberMixin<$Item>, 'rules'> & {
446
+ integer?: boolean
447
+ }
448
+ }
449
+
450
+ export type ComponentSchema<$Item = any> = BaseSchema<$Item> & {
451
+ type: 'component'
452
+ /**
453
+ * Use a Vue component to render the component. The component is specified
454
+ * like this: import(...).
455
+ */
456
+ component: Resolvable<VueConstructor<Vue>>
457
+ }
458
+
459
+ export type InputSchema<$Item = any> = BaseSchema<$Item> & {
460
+ /**
461
+ * The type of the component.
462
+ */
463
+ type:
464
+ | 'text'
465
+ | 'email'
466
+ | 'url'
467
+ | 'hostname'
468
+ | 'domain'
469
+ | 'tel'
470
+ | 'password'
471
+ | 'creditcard'
472
+ | 'computed'
473
+ rules?: {
474
+ text?: boolean
475
+ email?: boolean
476
+ url?: boolean
477
+ hostname?: boolean
478
+ domain?: boolean
479
+ // TODO: check why there is no 'tel' validation
480
+ // tel: boolean,
481
+ password?: boolean
482
+ creditcard?: boolean
483
+ }
484
+ }
485
+
486
+ export type DateSchema<$Item = any> = BaseSchema<$Item> & {
487
+ /**
488
+ * The type of the component.
489
+ */
490
+ type: 'date' | 'datetime' | 'time'
491
+ /**
492
+ * @defaultValue `En/US`
493
+ */
494
+ locale?: string
495
+ dateFormat?: OrItemAccessor<$Item, {}, DateFormat>
496
+ }
497
+
498
+ export type ButtonSchema<
499
+ $Item,
500
+ $EventHandler = ItemEventHandler<$Item>
501
+ > = BaseSchema<$Item> & {
502
+ /**
503
+ * The type of the component.
504
+ */
505
+ type: 'button' | 'submit'
506
+ closeForm?: OrItemAccessor<$Item, {}, boolean>
507
+ text?: OrItemAccessor<$Item, {}, string>
508
+ resource?: Resource
509
+ onClick?: $EventHandler
510
+ onSuccess?: $EventHandler
511
+ onError?: $EventHandler
512
+ events?: {
513
+ click?: $EventHandler
514
+ success?: $EventHandler
515
+ error?: $EventHandler
516
+ }
517
+ }
518
+
519
+ export type SwitchSchema<$Item = any> = BaseSchema<$Item> & {
520
+ /**
521
+ * The type of the component.
522
+ */
523
+ type: 'switch'
524
+ labels?: {
525
+ /**
526
+ * The displayed label when the switch is checked.
527
+ *
528
+ * @defaultValue `'on'`
529
+ */
530
+ checked?: string
531
+ /**
532
+ * The displayed label when the switch is unchecked.
533
+ *
534
+ * @defaultValue `'off'`
535
+ */
536
+ unchecked?: string
537
+ }
538
+ }
539
+
540
+ export type NumberSchema<$Item = any> = SchemaNumberMixin<$Item> &
541
+ BaseSchema<$Item> & {
542
+ /**
543
+ * The type of the component.
544
+ */
545
+ type: 'number' | 'integer'
546
+ }
547
+
548
+ export type SliderSchema<$Item = any> = SchemaNumberMixin<$Item> &
549
+ BaseSchema<$Item> & {
550
+ /**
551
+ * The type of the component.
552
+ */
553
+ type: 'slider'
554
+ // TODO: document what the input SliderSchema option does
555
+ input?: OrItemAccessor<$Item>
556
+ }
557
+
558
+ export type TextareaSchema<$Item = any> = BaseSchema<$Item> & {
559
+ /**
560
+ * The type of the component.
561
+ */
562
+ type: 'textarea'
563
+ /**
564
+ * Whether the input element is resizable.
565
+ */
566
+ resizable?: boolean
567
+ /**
568
+ * The amount of visible lines.
569
+ *
570
+ * @defaultValue `4`
571
+ */
572
+ lines?: number
573
+ }
574
+
575
+ export type CodeSchema<$Item = any> = BaseSchema<$Item> & {
576
+ /**
577
+ * The type of the component.
578
+ */
579
+ type: 'code'
580
+ /**
581
+ * The code language.
582
+ *
583
+ * @defaultValue `js`
584
+ */
585
+ language?: string
586
+ /**
587
+ * The indent size.
588
+ *
589
+ * @defaultValue `2`
590
+ */
591
+ indentSize?: number
592
+ /**
593
+ * The amount of visible lines.
594
+ *
595
+ * @defaultValue `3`
596
+ */
597
+ lines?: number
598
+ }
599
+
600
+ export type MarkupSchema<$Item = any> = BaseSchema<$Item> & {
601
+ /**
602
+ * The type of the component.
603
+ */
604
+ type: 'markup'
605
+ /**
606
+ * Whether the input element is resizable.
607
+ */
608
+ resizable?: OrItemAccessor<$Item, {}, boolean>
609
+ /**
610
+ * @defaultValue `'collapse'`
611
+ */
612
+ whitespace?: OrItemAccessor<
613
+ $Item,
614
+ {},
615
+ 'collapse' | 'preserve' | 'preserve-all'
616
+ >
617
+ /**
618
+ * The amount of visible lines.
619
+ *
620
+ * @defaultValue `10`
621
+ */
622
+ lines?: number
623
+
624
+ // TODO: document enableRules
625
+ enableRules?: OrItemAccessor<
626
+ $Item,
627
+ {},
628
+ | boolean
629
+ | {
630
+ input: boolean
631
+ paste: boolean
632
+ }
633
+ >
634
+ marks?: {
635
+ bold?: boolean
636
+ italic?: boolean
637
+ underline?: boolean
638
+ strike?: boolean
639
+ small?: boolean
640
+ code?: boolean
641
+ link?: boolean
642
+ }
643
+ nodes?: {
644
+ blockquote?: boolean
645
+ codeBlock?: boolean
646
+ heading?: (1 | 2 | 3 | 4 | 5 | 6)[]
647
+ horizontalRule?: boolean
648
+ orderedList?: boolean
649
+ bulletList?: boolean
650
+ }
651
+ tools?: {
652
+ history?: boolean
653
+ }
654
+ }
655
+
656
+ export type LabelSchema<$Item = any> = BaseSchema<$Item> & {
657
+ /**
658
+ * The type of the component.
659
+ */
660
+ type: 'label'
661
+ }
662
+
663
+ export type HiddenSchema<$Item = any> = BaseSchema<$Item> & {
664
+ /**
665
+ * The type of the component.
666
+ */
667
+ type: 'hidden'
668
+ }
669
+
670
+ export type UploadSchema<$Item = any> = BaseSchema<$Item> & {
671
+ /**
672
+ * The type of the component.
673
+ */
674
+ type: 'upload'
675
+ /**
676
+ * Whether multiple files can be uploaded.
677
+ *
678
+ * @default false
679
+ */
680
+ multiple?: boolean
681
+ /**
682
+ * Allowed file extensions for upload.
683
+ * @example 'zip' // Only files with zip extension
684
+ * @example ['jpg', 'jpeg', 'gif', 'png']
685
+ * @example /\.(gif|jpe?g|png)$/i
686
+ */
687
+ extensions?: OrArrayOf<RegExp | string>
688
+ /**
689
+ * One or more unique file type specifiers that describe the type of file
690
+ * that may be selected for upload by the user.
691
+ *
692
+ * @example 'audio/*' // Any type of audio file
693
+ * @example ['image/png', 'image/gif', 'image/jpeg']
694
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers }
695
+ */
696
+ accept?: OrArrayOf<string>
697
+ /**
698
+ * The maximum size of the file expressed as number of bytes or as a string
699
+ * like `'200kb'`, `'1mb'`, `'3.2gb'`, etc.
700
+ *
701
+ * @see {@link https://github.com/patrickkettner/filesize-parser/blob/master/test.js String Examples}
702
+ */
703
+ maxSize?: string | number
704
+ // TODO: UploadSchema draggable type
705
+ draggable?: boolean
706
+ /**
707
+ * Whether files can be deleted.
708
+ */
709
+ deletable?: boolean
710
+ }
711
+
712
+ export type MultiselectSchema<$Item = any, $Option = any> = BaseSchema<$Item> &
713
+ SchemaOptionsMixin<$Item, $Option> & {
714
+ /**
715
+ * The type of the component.
716
+ */
717
+ type: 'multiselect'
718
+ /**
719
+ * Whether more than one option can be selected.
720
+ *
721
+ * @defaultValue `false`
722
+ */
723
+ multiple?: boolean
724
+ // TODO: document searchable
725
+ /**
726
+ * @defaultValue `false`
727
+ */
728
+ searchable?: boolean
729
+ // TODO: document stayOpen
730
+ /**
731
+ * @defaultValue `false`
732
+ */
733
+ stayOpen?: boolean
734
+ /**
735
+ * When defined, a search input field will be added to allow searching for
736
+ * specific options.
737
+ */
738
+ search?: {
739
+ filter?: ItemAccessor<$Item, { query: string }, OrPromiseOf<$Option[]>>
740
+ debounce?:
741
+ | number
742
+ | {
743
+ delay: number
744
+ immediate?: boolean
745
+ }
746
+ }
747
+ /**
748
+ * @defaultValue `false`
749
+ */
750
+ // TODO: document taggable
751
+ taggable?: boolean
752
+ }
753
+
754
+ export type SelectSchema<$Item = any> = BaseSchema<$Item> &
755
+ SchemaOptionsMixin<$Item> & {
756
+ /**
757
+ * The type of the component.
758
+ */
759
+ type: 'select'
760
+ }
761
+
762
+ export type RadioSchema<$Item = any> = BaseSchema<$Item> &
763
+ SchemaOptionsMixin<$Item> & {
764
+ /**
765
+ * The type of the component.
766
+ */
767
+ type: 'radio'
768
+ /**
769
+ * @defaultValue `'vertical'`
770
+ */
771
+ layout?: 'horizontal' | 'vertical'
772
+ }
773
+
774
+ export type SectionSchema<$Item = any> = BaseSchema<$Item> & {
775
+ /**
776
+ * The type of the component.
777
+ */
778
+ type: 'section'
779
+ components?: Components<$Item>
780
+ }
781
+
782
+ export type CheckboxSchema<$Item = any> = BaseSchema<$Item> & {
783
+ /**
784
+ * The type of the component.
785
+ */
786
+ type: 'checkbox'
787
+ }
788
+
789
+ export type CheckboxesSchema<$Item = any> = BaseSchema<$Item> &
790
+ SchemaOptionsMixin<$Item> & {
791
+ /**
792
+ * The type of the component.
793
+ */
794
+ type: 'checkboxes'
795
+ /**
796
+ * @defaultValue `'vertical'`
797
+ */
798
+ layout?: 'horizontal' | 'vertical'
799
+ }
800
+
801
+ export type ColorFormat =
802
+ | 'rgb'
803
+ | 'prgb'
804
+ | 'hex'
805
+ | 'hex6'
806
+ | 'hex3'
807
+ | 'hex4'
808
+ | 'hex8'
809
+ | 'name'
810
+ | 'hsl'
811
+ | 'hsv'
812
+ export type ColorSchema<$Item = any> = BaseSchema<$Item> & {
813
+ /**
814
+ * The type of the component.
815
+ */
816
+ type: 'color'
817
+ /**
818
+ * The color format.
819
+ */
820
+ format?: OrItemAccessor<$Item, {}, ColorFormat>
821
+ /**
822
+ * Whether the color may contain an alpha component.
823
+ *
824
+ * @defaultValue `false`
825
+ */
826
+ alpha?: OrItemAccessor<$Item, {}, boolean>
827
+ /**
828
+ * @defaultValue true
829
+ */
830
+ // TODO: document inputs
831
+ /**
832
+ * @defaultValue `true`
833
+ */
834
+ inputs?: OrItemAccessor<$Item, {}, boolean>
835
+ /**
836
+ * Color presets as an array of color values as strings in any css
837
+ * compatible format.
838
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value}
839
+ */
840
+ presets?: OrItemAccessor<$Item, {}, string[]>
841
+ }
842
+
843
+ export type ColumnSchema<$Item = any> = {
844
+ /**
845
+ * The label of the column.
846
+ * @defaultValue The labelized column key.
847
+ */
848
+ label?: string
849
+ /**
850
+ * Use a Vue component to render the cell. The component is specified
851
+ * like this: import(...).
852
+ */
853
+ component?: Resolvable<VueConstructor<Vue>>
854
+ /**
855
+ * Whether the column should be sortable.
856
+ */
857
+ sortable?: boolean
858
+ /**
859
+ * A function of the value and the item returning the displayed name.
860
+ * If the column is sortable, the column is sorted by value and not by
861
+ * rendered name.
862
+ */
863
+ render?: ItemAccessor<$Item, {}, string>
864
+ /**
865
+ * The provided string is applied to the class property of the column
866
+ * cell html elements.
867
+ */
868
+ class?: string
869
+ /**
870
+ * The provided string is applied to the style property of the column
871
+ * cell html elements.
872
+ */
873
+ style?: string | Partial<CSSStyleDeclaration>
874
+ /**
875
+ * Sort the colum in ascending or descending order. Columns are ordered by the
876
+ * first column to specify `defaultSort`.
877
+ */
878
+ defaultSort?: 'asc' | 'desc'
879
+ /**
880
+ * Only displays the column if the item accessor returns `true`
881
+ */
882
+ if?: ItemAccessor<$Item, {}, boolean>
883
+ }
884
+
885
+ export type ResolvableForm<$Item = any> = Resolvable<Form<$Item>>
886
+
887
+ export type ListSchema<$Item = { [key: string]: any }> =
888
+ SchemaSourceMixin<$Item> &
889
+ BaseSchema<$Item> & {
890
+ /**
891
+ * The type of the view
892
+ */
893
+ type: 'list'
894
+ /**
895
+ * The form.
896
+ */
897
+ form?: ResolvableForm
898
+ /**
899
+ * The forms.
900
+ */
901
+ forms?: {
902
+ [key: string]: ResolvableForm
903
+ }
904
+ /**
905
+ * The label given to the items. If no itemLabel is given, the default is
906
+ * the 'name' property of the item, followed by label of the form of the
907
+ * view (plus item id) and other defaults.
908
+ */
909
+ itemLabel?: OrItemAccessor<any, {}, string>
910
+ /**
911
+ * The columns displayed in the table. While columns can be supplied as an
912
+ * array where each entry is the name of a property of the item, it is
913
+ * usually beneficial to assign an object with further options to the
914
+ * columns property.
915
+ */
916
+ columns?: Record<string, ColumnSchema<$Item>> | (keyof $Item)[]
917
+ /**
918
+ * Scope names as defined on the model. When set, the admin renders a set
919
+ * of scope buttons, allowing the user to switch between them while
920
+ * editing.
921
+ */
922
+ scopes?:
923
+ | string[]
924
+ | {
925
+ [scopeName: string]:
926
+ | {
927
+ label?: string
928
+ hint?: string
929
+ defaultScope?: boolean
930
+ }
931
+ | string
932
+ }
933
+ /**
934
+ * Default scope name as defined on the model.
935
+ */
936
+ scope?: string
937
+
938
+ // TODO: document filters
939
+ filters?: {
940
+ [k: string]:
941
+ | {
942
+ label?: string
943
+ filter: 'text'
944
+ /**
945
+ * @defaultValue `['contains']`
946
+ */
947
+ operators?: (
948
+ | 'contains'
949
+ | 'equals'
950
+ | 'starts-with'
951
+ | 'ends-with'
952
+ )[]
953
+ }
954
+ | {
955
+ label?: string
956
+ filter: 'date-range'
957
+ }
958
+ | {
959
+ label?: string
960
+ components: Components<any>
961
+ }
962
+ }
963
+ }
964
+
965
+ export type OrItemAccessor<
966
+ $Item = any,
967
+ $Params extends {} = {},
968
+ $ReturnValue = any
969
+ > = ItemAccessor<$Item, $Params, $ReturnValue> | $ReturnValue
970
+
971
+ export type ItemAccessor<
972
+ $Item = any,
973
+ $Params extends {} = {},
974
+ $ReturnValue = any
975
+ > = (params: DitoContext<$Item> & $Params) => $ReturnValue
976
+
977
+ export type DitoContext<$Item = any> = {
978
+ /**
979
+ * `nested` is `true` when the data-path points a value inside an item, and
980
+ * `false` when it points to the item itself.
981
+ */
982
+ nested: boolean
983
+ value: any
984
+ dataPath: string
985
+ name: string
986
+ index: any
987
+ itemDataPath: any
988
+ parentItemDataPath: any
989
+ itemIndex: any
990
+ parentItemIndex: any
991
+ item: $Item
992
+ /**
993
+ * NOTE: `parentItem` isn't the closest data parent to `item`, it's the
994
+ * closest parent that isn't an array, e.g. for relations or nested JSON
995
+ * data. This is why the term `item` was chosen over `data`, e.g. VS the
996
+ * use of `parentData` in server-sided validation, which is the closest
997
+ * parent. If needed, we could expose this data here too, as we can do all
998
+ * sorts of data processing with `rootData` and `dataPath`.
999
+ */
1000
+ parentItem: any
1001
+ rootItem: any
1002
+ processedItem: any
1003
+ clipboardItem: any
1004
+ user: {
1005
+ roles?: string[]
1006
+ hasRole(...roles: string[]): boolean
1007
+ }
1008
+ api: ApiConfig
1009
+ views: any
1010
+ itemLabel: string | null
1011
+ formLabel: string | null
1012
+ component: any
1013
+ schemaComponent: Vue | null
1014
+ formComponent: any
1015
+ viewComponent: any
1016
+ dialogComponent: any
1017
+ panelComponent: Vue | null
1018
+ resourceComponent: Vue | null
1019
+ sourceComponent: Vue | null
1020
+ option: any
1021
+ options: any
1022
+ query: string
1023
+ error: any | null
1024
+ wasNotified: boolean
1025
+
1026
+ // Helper Methods
1027
+
1028
+ request<T>(options: {
1029
+ /**
1030
+ * Allows caching of loaded data on two levels:
1031
+ * - 'global': cache globally, for the entire admin session
1032
+ * - 'local': cache locally within the closest route component that is
1033
+ * associated with a resource and loads its own data.
1034
+ */
1035
+ cache?: 'local' | 'global'
1036
+ url: string
1037
+ /**
1038
+ * @defaultValue `'get'`
1039
+ */
1040
+ method?: HTTPVerb
1041
+ params?: any
1042
+ data?: any
1043
+ }): Promise<T>
1044
+ format: typeof utilsFormat
1045
+ navigate(location: string | { path: string }): Promise<boolean>
1046
+ download: {
1047
+ (url: string): void
1048
+ (options: { url: string; filename: string }): void
1049
+ }
1050
+ getResourceUrl: any
1051
+ notify(options: {
1052
+ type?: LiteralUnion<'warning' | 'error' | 'info' | 'success'>
1053
+ title?: string
1054
+ text: OrArrayOf<string>
1055
+ }): void
1056
+ }
1057
+
1058
+ export type View<$Item = any> = {
1059
+ resource?: Form['resource']
1060
+ clipboard?: Form['clipboard']
1061
+ } & (
1062
+ | InputSchema<$Item>
1063
+ | RadioSchema<$Item>
1064
+ | CheckboxSchema<$Item>
1065
+ | CheckboxesSchema<$Item>
1066
+ | ColorSchema<$Item>
1067
+ | SelectSchema<$Item>
1068
+ | MultiselectSchema<$Item>
1069
+ | ListSchema<$Item>
1070
+ | TextareaSchema<$Item>
1071
+ | CodeSchema<$Item>
1072
+ | NumberSchema<$Item>
1073
+ | SliderSchema<$Item>
1074
+ | UploadSchema<$Item>
1075
+ | MarkupSchema<$Item>
1076
+ | ButtonSchema<$Item>
1077
+ | SwitchSchema<$Item>
1078
+ | DateSchema<$Item>
1079
+ | ComponentSchema<$Item>
1080
+ | LabelSchema<$Item>
1081
+ | SectionSchema<$Item>
1082
+ | HiddenSchema<$Item>
1083
+ )
1084
+
1085
+ export type Component<$Item = any> =
1086
+ | InputSchema<$Item>
1087
+ | RadioSchema<$Item>
1088
+ | CheckboxSchema<$Item>
1089
+ | CheckboxesSchema<$Item>
1090
+ | ColorSchema<$Item>
1091
+ | SelectSchema<$Item>
1092
+ | MultiselectSchema<$Item>
1093
+ | ListSchema<$Item>
1094
+ | TextareaSchema<$Item>
1095
+ | CodeSchema<$Item>
1096
+ | NumberSchema<$Item>
1097
+ | SliderSchema<$Item>
1098
+ | UploadSchema<$Item>
1099
+ | MarkupSchema<$Item>
1100
+ | ButtonSchema<$Item>
1101
+ | SwitchSchema<$Item>
1102
+ | DateSchema<$Item>
1103
+ | ComponentSchema<$Item>
1104
+ | LabelSchema<$Item>
1105
+ | SectionSchema<$Item>
1106
+ | HiddenSchema<$Item>
1107
+
1108
+ export type Components<$Item = any> = {
1109
+ [$name: string]: Component<$Item>
1110
+ }
1111
+
1112
+ export type Buttons<$Item> = Record<
1113
+ string,
1114
+ SetOptional<ButtonSchema<$Item>, 'type'>
1115
+ >
1116
+
1117
+ export type Form<$Item = any> = {
1118
+ /**
1119
+ * The name of the item model produced by the form.
1120
+ */
1121
+ name?: OrItemAccessor<$Item, {}, string>
1122
+ /**
1123
+ * The label of the form.
1124
+ */
1125
+ label?: OrItemAccessor<$Item, {}, string | boolean>
1126
+ /**
1127
+ * @defaultValue `false`
1128
+ */
1129
+ compact?: boolean
1130
+ resource?: Resource
1131
+ /**
1132
+ * Display several forms in different tabs within the form.
1133
+ */
1134
+ tabs?: Record<
1135
+ string,
1136
+ Omit<Form<$Item>, 'tabs'> & {
1137
+ defaultTab?: OrItemAccessor<$Item, {}, boolean>
1138
+ }
1139
+ >
1140
+ // TODO: document components
1141
+ components?: Components<$Item>
1142
+ // TODO: document clipboard
1143
+ clipboard?:
1144
+ | boolean
1145
+ | {
1146
+ copy?: (...args: any[]) => any
1147
+ paste?: (...args: any[]) => any
1148
+ }
1149
+ buttons?: Buttons<$Item>
1150
+ if?: OrItemAccessor<$Item, {}, boolean>
1151
+ }
1152
+
1153
+ export type Resource =
1154
+ | string
1155
+ | RequireAtLeastOne<{
1156
+ path?: string
1157
+ method?: HTTPVerb
1158
+ // TODO: type Resource['data']
1159
+ data?: any
1160
+ }>
1161
+
1162
+ export class DitoAdmin<
1163
+ $Views extends Record<string, any> = Record<string, OrPromiseOf<View>>
1164
+ > {
1165
+ api: ApiConfig
1166
+ // TODO: finish off Vue types
1167
+ root: Vue
1168
+ constructor(
1169
+ element: Element | string,
1170
+ options?: {
1171
+ // `dito` contains the base and api settings passed from `AdminController`
1172
+ dito?: DitoGlobal
1173
+ api?: ApiConfig
1174
+ views: OrFunctionReturning<OrPromiseOf<$Views>>
1175
+ // TODO: options rest type
1176
+ // ...options: any
1177
+ }
1178
+ )
1179
+
1180
+ // TODO: options and return type
1181
+ register(type: OrArrayOf<string>, options: any): any
1182
+ request: RequestMethod
1183
+ }
1184
+ export type HTTPVerb = 'get' | 'post' | 'put' | 'delete' | 'patch'
1185
+
1186
+ export type SchemaByType<$Item = any> = {
1187
+ button: ButtonSchema<$Item>
1188
+ checkbox: CheckboxSchema<$Item>
1189
+ checkboxes: CheckboxesSchema<$Item>
1190
+ code: CodeSchema<$Item>
1191
+ color: ColorSchema<$Item>
1192
+ component: ComponentSchema<$Item>
1193
+ date: DateSchema<$Item>
1194
+ list: ListSchema<$Item>
1195
+ markup: MarkupSchema<$Item>
1196
+ multiselect: MultiselectSchema<$Item>
1197
+ number: NumberSchema<$Item>
1198
+ radio: RadioSchema<$Item>
1199
+ select: SelectSchema<$Item>
1200
+ slider: SliderSchema<$Item>
1201
+ switch: SwitchSchema<$Item>
1202
+ text: InputSchema<$Item>
1203
+ textarea: TextareaSchema<$Item>
1204
+ upload: UploadSchema<$Item>
1205
+ label: LabelSchema<$Item>
1206
+ section: SectionSchema<$Item>
1207
+ hidden: HiddenSchema<$Item>
1208
+ unknown: never
1209
+ }
1210
+
1211
+ type OrRecordOf<T> = T | Record<string, T>
1212
+ type OrPromiseOf<T> = T | Promise<T>
1213
+ type OrFunctionReturning<T> = (() => T) | T
1214
+ type OrArrayOf<T> = T | T[]
1215
+ type Resolvable<T> = OrFunctionReturning<OrPromiseOf<OrRecordOf<T>>>
1216
+
1217
+ // https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360
1218
+ type AnyGate<
1219
+ $CheckType,
1220
+ $TypeWhenNotAny,
1221
+ $TypeWhenAny = $CheckType
1222
+ > = 0 extends 1 & $CheckType ? $TypeWhenAny : $TypeWhenNotAny
1223
+
1224
+ type LiteralUnion<T extends U, U = string> = T | (U & Record<never, never>)