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