@drax/crud-vue 3.1.0 → 3.2.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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "3.1.0",
6
+ "version": "3.2.1",
7
7
  "type": "module",
8
8
  "main": "./src/index.ts",
9
9
  "module": "./src/index.ts",
@@ -26,8 +26,8 @@
26
26
  "dependencies": {
27
27
  "@drax/common-front": "^3.0.0",
28
28
  "@drax/crud-front": "^3.0.0",
29
- "@drax/crud-share": "^3.1.0",
30
- "@drax/media-vue": "^3.1.0"
29
+ "@drax/crud-share": "^3.2.0",
30
+ "@drax/media-vue": "^3.2.1"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "pinia": "^3.0.4",
@@ -50,5 +50,5 @@
50
50
  "vue-tsc": "^3.2.4",
51
51
  "vuetify": "^3.11.8"
52
52
  },
53
- "gitHead": "262ea8f861c84ca1ad4d555545c5a94b95dbf25e"
53
+ "gitHead": "f6c0a2464fdd61b2434d85a097ad23bdbb1d7954"
54
54
  }
package/src/EntityCrud.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import type {
2
2
  IEntityCrud, IEntityCrudForm, IEntityCrudHeader, IEntityCrudRefs,
3
3
  IEntityCrudRules, IEntityCrudField, IEntityCrudPermissions,
4
- IDraxCrudProvider, IEntityCrudFilter, IEntityCrudFieldVariant, IDraxFieldFilter
4
+ IDraxCrudProvider, IEntityCrudFilter, IEntityCrudFieldVariant, IDraxFieldFilter,
5
+ IEntityCrudOnInput
5
6
  } from "@drax/crud-share";
6
7
 
7
8
 
@@ -149,10 +150,20 @@ class EntityCrud implements IEntityCrud {
149
150
  return {}
150
151
  }
151
152
 
153
+
154
+
152
155
  getRule(field: string | undefined): Array<Function> | undefined {
153
156
  return field && this.rules[field] && this.rules[field].length > 0 ? this.rules[field] : undefined
154
157
  }
155
158
 
159
+ get onInputs(): IEntityCrudOnInput {
160
+ return {}
161
+ }
162
+
163
+ getOnInput(field: string | undefined): Function | undefined {
164
+ return (field && this.onInputs[field] && typeof this.onInputs[field] === 'function') ? this.onInputs[field] : undefined
165
+ }
166
+
156
167
  get isViewable() {
157
168
  return true
158
169
  }
@@ -27,6 +27,7 @@ const {entity, multiple} = defineProps({
27
27
  hint: {type: String},
28
28
  persistentHint: {type: Boolean, default: false},
29
29
  rules: {type: Array as PropType<any>, default: () => []},
30
+ onInput: {type: Function as PropType<Function>, required: false},
30
31
  errorMessages: {type: Array as PropType<string[]>, default: () => []},
31
32
  hideDetails: {type: Boolean, default: false},
32
33
  singleLine: {type: Boolean, default: false},
@@ -128,11 +129,17 @@ defineEmits(['updateValue'])
128
129
  :single-line="singleLine"
129
130
  :clearable="clearable"
130
131
  :error-messages="errorMessages"
131
- @update:modelValue="$emit('updateValue')"
132
+ @update:modelValue="v => {
133
+ if(onInput && typeof onInput === 'function'){
134
+ onInput(v)
135
+ }
136
+ $emit('updateValue')
137
+ }"
132
138
  :prepend-icon="prependIcon"
133
139
  :append-icon="appendIcon"
134
140
  :prepend-inner-icon="prependInnerIcon"
135
141
  :append-inner-icon="appendInnerIcon"
142
+ @input="onInput"
136
143
  >
137
144
 
138
145
  <template v-if="addOnTheFly" v-slot:append>
@@ -185,11 +192,17 @@ defineEmits(['updateValue'])
185
192
  :clearable="clearable"
186
193
  :error-messages="errorMessages"
187
194
  @update:search="debouncedSearch"
188
- @update:modelValue="$emit('updateValue')"
195
+ @update:modelValue="v => {
196
+ if(onInput && typeof onInput === 'function'){
197
+ onInput(v)
198
+ }
199
+ $emit('updateValue')
200
+ }"
189
201
  :prepend-icon="prependIcon"
190
202
  :append-icon="appendIcon"
191
203
  :prepend-inner-icon="prependInnerIcon"
192
204
  :append-inner-icon="appendInnerIcon"
205
+ @input="onInput"
193
206
  >
194
207
 
195
208
  <template v-if="addOnTheFly" v-slot:append>
@@ -132,6 +132,12 @@ const rules = computed(() => {
132
132
  }
133
133
  })
134
134
 
135
+ const onInput = computed(() => {
136
+ return (fieldName: string) => {
137
+ return entity?.getOnInput(fieldName) as Function || undefined
138
+ }
139
+ })
140
+
135
141
  const onlyView = computed(()=> {
136
142
  return ['delete','view'].includes(operation?.value)
137
143
  })
@@ -177,6 +183,7 @@ const onlyView = computed(()=> {
177
183
  :preview="field?.preview"
178
184
  :previewHeight="field?.previewHeight"
179
185
  :rules="rules(field.name)"
186
+ :on-input="onInput(field.name)"
180
187
  :hint="field.hint"
181
188
  :persistent-hint="field.persistentHint"
182
189
  :placeholder="field.placeholder"
@@ -226,6 +233,7 @@ const onlyView = computed(()=> {
226
233
  :append-icon="field?.appendIcon"
227
234
  :append-inner-icon="field?.appendInnerIcon"
228
235
  :rules="rules(field.name)"
236
+ :on-input="onInput(field.name)"
229
237
  :hint="field.hint"
230
238
  :persistent-hint="field.persistentHint"
231
239
  :placeholder="field.placeholder"
@@ -284,6 +292,7 @@ const onlyView = computed(()=> {
284
292
  :append-icon="field?.appendIcon"
285
293
  :append-inner-icon="field?.appendInnerIcon"
286
294
  :rules="rules(field.name)"
295
+ :on-input="onInput(field.name)"
287
296
  :hint="field.hint"
288
297
  :persistent-hint="field.persistentHint"
289
298
  :placeholder="field.placeholder"
@@ -16,14 +16,13 @@ import MediaField from "@drax/media-vue/src/components/MediaField.vue";
16
16
  import MediaFullField from "@drax/media-vue/src/components/MediaFullField.vue";
17
17
 
18
18
 
19
-
20
19
  const {t, te} = useI18n()
21
20
 
22
21
  const {hasPermission} = useAuth()
23
22
 
24
23
  const valueModel = defineModel<any>({type: [String, Number, Boolean, Object, Array], default: false})
25
24
 
26
- const {index, entity, field, parentField, errorMessages, rules, readonly, hideDetails} = defineProps({
25
+ const {index, entity, field, parentField, errorMessages, rules, onInput, readonly, hideDetails} = defineProps({
27
26
  entity: {type: Object as PropType<IEntityCrud>, required: true},
28
27
  field: {type: Object as PropType<IEntityCrudField | IEntityCrudFilter | undefined>, required: true},
29
28
  prependIcon: {type: String, default: ''},
@@ -43,6 +42,7 @@ const {index, entity, field, parentField, errorMessages, rules, readonly, hideDe
43
42
  previewHeight: {type: String, default: '100px'},
44
43
  parentField: {type: String, default: null, required: false},
45
44
  errorMessages: {type: Array as PropType<string[]>, default: null, required: false},
45
+ onInput: {type: Function as PropType<Function>, required: false},
46
46
  rules: {type: Array as PropType<ValidationRule[]>, required: false},
47
47
  index: {type: Number, default: null, required: false},
48
48
  density: {type: String as PropType<'comfortable' | 'compact' | 'default'>, default: 'default'},
@@ -69,11 +69,10 @@ const label = computed(() => {
69
69
  })
70
70
 
71
71
 
72
-
73
72
  const storeErrorMessages = computed(() => {
74
73
  let sIndex = (index != null && index >= 0) ? `${index}.` : ''
75
74
  let name = parentField ? `${parentField}.${sIndex}${field.name}` : field.name
76
- return store.getFieldInputErrors(name).map((error: string) =>te(error) ? t(error) : error)
75
+ return store.getFieldInputErrors(name).map((error: string) => te(error) ? t(error) : error)
77
76
  }
78
77
  )
79
78
 
@@ -84,10 +83,10 @@ const inputErrors = computed(() => {
84
83
  defineEmits(['updateValue'])
85
84
 
86
85
 
87
- const hasHideDetails = computed(()=>{
88
- if(readonly){
86
+ const hasHideDetails = computed(() => {
87
+ if (readonly) {
89
88
  return true
90
- }else{
89
+ } else {
91
90
  return hideDetails ?? field.hideDetails
92
91
  }
93
92
 
@@ -120,6 +119,7 @@ const hasHideDetails = computed(()=>{
120
119
  :append-icon="appendIcon"
121
120
  :prepend-inner-icon="prependInnerIcon"
122
121
  :append-inner-icon="appendInnerIcon"
122
+ @input="onInput"
123
123
  @update:modelValue="$emit('updateValue')"
124
124
  />
125
125
 
@@ -147,6 +147,7 @@ const hasHideDetails = computed(()=>{
147
147
  :prepend-inner-icon="prependInnerIcon"
148
148
  :append-inner-icon="appendInnerIcon"
149
149
  @update:modelValue="$emit('updateValue')"
150
+ @input="onInput"
150
151
  />
151
152
 
152
153
  <v-text-field
@@ -169,10 +170,11 @@ const hasHideDetails = computed(()=>{
169
170
  :prepend-icon="prependIcon"
170
171
  :append-icon="appendIcon"
171
172
  :prepend-inner-icon="prependInnerIcon"
172
- @update:modelValue="$emit('updateValue')"
173
173
  :type="show ? 'text' : 'password'"
174
174
  :append-inner-icon="show ? 'mdi-eye' : 'mdi-eye-off'"
175
175
  @click:append-inner="show = !show"
176
+ @update:modelValue="$emit('updateValue')"
177
+ @input="onInput"
176
178
  />
177
179
 
178
180
 
@@ -194,12 +196,17 @@ const hasHideDetails = computed(()=>{
194
196
  :hide-details="hasHideDetails"
195
197
  :single-line="singleLine"
196
198
  :rules="rules"
197
- @update:modelValue="$emit('updateValue')"
199
+ @update:modelValue="v => {
200
+ if(onInput && typeof onInput === 'function'){
201
+ onInput(v)
202
+ }
203
+ $emit('updateValue')
204
+ }"
198
205
  :prepend-icon="prependIcon"
199
206
  :append-icon="appendIcon"
200
207
  :prepend-inner-icon="prependInnerIcon"
201
208
  :append-inner-icon="appendInnerIcon"
202
-
209
+ @input="onInput"
203
210
  >
204
211
  </v-combobox>
205
212
 
@@ -223,12 +230,17 @@ const hasHideDetails = computed(()=>{
223
230
  :hide-details="hasHideDetails"
224
231
  :single-line="singleLine"
225
232
  :rules="rules"
226
- @update:modelValue="$emit('updateValue')"
233
+ @update:modelValue="v => {
234
+ if(onInput && typeof onInput === 'function'){
235
+ onInput(v)
236
+ }
237
+ $emit('updateValue')
238
+ }"
227
239
  :prepend-icon="prependIcon"
228
240
  :append-icon="appendIcon"
229
241
  :prepend-inner-icon="prependInnerIcon"
230
242
  :append-inner-icon="appendInnerIcon"
231
-
243
+ @input="onInput"
232
244
  >
233
245
  <template v-slot:item="{ props: itemProps, item }">
234
246
  <v-list-item
@@ -242,7 +254,10 @@ const hasHideDetails = computed(()=>{
242
254
  </template>
243
255
 
244
256
  <template v-slot:selection="{item}">
245
- <v-chip tile density="compact" :color="item.raw.color" :prepend-icon="item.raw.icon">{{ item.raw.title }}</v-chip>
257
+ <v-chip tile density="compact" :color="item.raw.color" :prepend-icon="item.raw.icon">{{
258
+ item.raw.title
259
+ }}
260
+ </v-chip>
246
261
  </template>
247
262
  </v-select>
248
263
 
@@ -270,11 +285,11 @@ const hasHideDetails = computed(()=>{
270
285
  :append-icon="appendIcon"
271
286
  :prepend-inner-icon="prependInnerIcon"
272
287
  :append-inner-icon="appendInnerIcon"
288
+ @input="onInput"
273
289
  >
274
290
  </v-select>
275
291
 
276
292
 
277
-
278
293
  <v-text-field
279
294
  v-if="field.type === 'number'"
280
295
  type="number"
@@ -298,6 +313,7 @@ const hasHideDetails = computed(()=>{
298
313
  :append-icon="appendIcon"
299
314
  :prepend-inner-icon="prependInnerIcon"
300
315
  :append-inner-icon="appendInnerIcon"
316
+ @input="onInput"
301
317
  />
302
318
 
303
319
  <media-field
@@ -367,6 +383,7 @@ const hasHideDetails = computed(()=>{
367
383
  :prepend-inner-icon="prependInnerIcon"
368
384
  :append-inner-icon="appendInnerIcon"
369
385
  color="primary"
386
+ @input="onInput"
370
387
  />
371
388
 
372
389
 
@@ -375,7 +392,8 @@ const hasHideDetails = computed(()=>{
375
392
  :name="name"
376
393
  :label="label"
377
394
  :hint="hint ?? field.hint"
378
- :persistent-hint="persistentHint ?? field.persistentHint" :placeholder="placeholder ?? field.placeholder" :persistent-placeholder="persistentPlaceholder ?? field.persistentPlaceholder"
395
+ :persistent-hint="persistentHint ?? field.persistentHint" :placeholder="placeholder ?? field.placeholder"
396
+ :persistent-placeholder="persistentPlaceholder ?? field.persistentPlaceholder"
379
397
  v-model="valueModel"
380
398
  :readonly="readonly"
381
399
  :error-messages="inputErrors"
@@ -391,6 +409,9 @@ const hasHideDetails = computed(()=>{
391
409
  date.setHours(23, 59, 59, 0)
392
410
  valueModel = date
393
411
  }
412
+ if(onInput && typeof onInput === 'function'){
413
+ onInput(v)
414
+ }
394
415
  $emit('updateValue')
395
416
  }"
396
417
  @click:clear="() => {valueModel = null; $emit('updateValue');} "
@@ -399,6 +420,7 @@ const hasHideDetails = computed(()=>{
399
420
  :prepend-inner-icon="prependInnerIcon"
400
421
  :append-inner-icon="appendInnerIcon"
401
422
  :max="field.max"
423
+ @input="onInput"
402
424
  >
403
425
  <template v-if="field.endOfDay && field.showEndOfDayChip !== false" v-slot:append-inner>
404
426
  <v-chip size="small">23:59</v-chip>
@@ -431,6 +453,7 @@ const hasHideDetails = computed(()=>{
431
453
  :prepend-inner-icon="prependInnerIcon"
432
454
  :append-inner-icon="appendInnerIcon"
433
455
  :add-on-the-fly="field?.addOnTheFly"
456
+ :on-input="onInput"
434
457
  />
435
458
 
436
459
  <v-card v-if="field.type === 'object'" class="mt-3" variant="flat" border>
@@ -439,7 +462,7 @@ const hasHideDetails = computed(()=>{
439
462
  <v-card-text>
440
463
 
441
464
  <v-row dense>
442
- <v-col cols="12" v-for="oField in field.objectFields">
465
+ <v-col cols="12" v-for="oField in field.objectFields">
443
466
  <crud-form-field
444
467
 
445
468
  :entity="entity"
@@ -487,11 +510,17 @@ const hasHideDetails = computed(()=>{
487
510
  :hide-details="hasHideDetails"
488
511
  :single-line="singleLine"
489
512
  :rules="rules"
490
- @update:modelValue="$emit('updateValue')"
513
+ @update:modelValue="v => {
514
+ if(onInput && typeof onInput === 'function'){
515
+ onInput(v)
516
+ }
517
+ $emit('updateValue')
518
+ }"
491
519
  :prepend-icon="prependIcon"
492
520
  :append-icon="appendIcon"
493
521
  :prepend-inner-icon="prependInnerIcon"
494
522
  :append-inner-icon="appendInnerIcon"
523
+ @input="onInput"
495
524
  >
496
525
  </v-combobox>
497
526
 
@@ -517,11 +546,17 @@ const hasHideDetails = computed(()=>{
517
546
  :hide-details="hasHideDetails"
518
547
  :single-line="singleLine"
519
548
  :rules="rules"
520
- @update:modelValue="$emit('updateValue')"
549
+ @update:modelValue="v => {
550
+ if(onInput && typeof onInput === 'function'){
551
+ onInput(v)
552
+ }
553
+ $emit('updateValue')
554
+ }"
521
555
  :prepend-icon="prependIcon"
522
556
  :append-icon="appendIcon"
523
557
  :prepend-inner-icon="prependInnerIcon"
524
558
  :append-inner-icon="appendInnerIcon"
559
+ @input="onInput"
525
560
  >
526
561
  </v-combobox>
527
562
 
@@ -553,6 +588,7 @@ const hasHideDetails = computed(()=>{
553
588
  :prepend-inner-icon="prependInnerIcon"
554
589
  :append-inner-icon="appendInnerIcon"
555
590
  :add-on-the-fly="field?.addOnTheFly"
591
+ :on-input="onInput"
556
592
  />
557
593
 
558
594
 
@@ -565,7 +601,7 @@ const hasHideDetails = computed(()=>{
565
601
  :persistent-hint="persistentHint ?? field.persistentHint"
566
602
  :placeholder="placeholder ?? field.placeholder"
567
603
  :persistent-placeholder="persistentPlaceholder ?? field.persistentPlaceholder"
568
- v-model ="valueModel"
604
+ v-model="valueModel"
569
605
  :multiple="true"
570
606
  :chips="true"
571
607
  :readonly="readonly"
@@ -576,11 +612,17 @@ const hasHideDetails = computed(()=>{
576
612
  :hide-details="hasHideDetails"
577
613
  :single-line="singleLine"
578
614
  :rules="rules"
579
- @update:modelValue="$emit('updateValue')"
615
+ @update:modelValue="v => {
616
+ if(onInput && typeof onInput === 'function'){
617
+ onInput(v)
618
+ }
619
+ $emit('updateValue')
620
+ }"
580
621
  :prepend-icon="prependIcon"
581
622
  :append-icon="appendIcon"
582
623
  :prepend-inner-icon="prependInnerIcon"
583
624
  :append-inner-icon="appendInnerIcon"
625
+ @input="onInput"
584
626
  >
585
627
  </v-combobox>
586
628
 
@@ -39,6 +39,14 @@ export const useCrudStore = (id: string = 'entity') => defineStore('CrudStore'+i
39
39
  }
40
40
  ),
41
41
  getters: {
42
+ getFieldValue(state: any) {
43
+ return (fieldName: string) => {
44
+ if (fieldName && state.form[fieldName]) {
45
+ return state.form[fieldName]
46
+ }
47
+ return undefined
48
+ }
49
+ },
42
50
  getFieldInputErrors(state: any) {
43
51
  return (fieldName: string) => {
44
52
  if (state.inputErrors && state.inputErrors[fieldName]) {