@drax/crud-vue 0.46.0 → 0.49.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
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.46.0",
6
+ "version": "0.49.0",
7
7
  "type": "module",
8
8
  "main": "./src/index.ts",
9
9
  "module": "./src/index.ts",
@@ -24,10 +24,10 @@
24
24
  "format": "prettier --write src/"
25
25
  },
26
26
  "dependencies": {
27
- "@drax/common-front": "^0.46.0",
28
- "@drax/crud-front": "^0.46.0",
29
- "@drax/crud-share": "^0.46.0",
30
- "@drax/media-vue": "^0.46.0"
27
+ "@drax/common-front": "^0.49.0",
28
+ "@drax/crud-front": "^0.49.0",
29
+ "@drax/crud-share": "^0.49.0",
30
+ "@drax/media-vue": "^0.49.0"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "pinia": "^2.2.2",
@@ -64,5 +64,5 @@
64
64
  "vue-tsc": "^2.1.10",
65
65
  "vuetify": "^3.8.2"
66
66
  },
67
- "gitHead": "9625999c86d538dc3bee7c501acba6c51592ebca"
67
+ "gitHead": "ea99f6fd79d282e6efe02fca660d5733c13bb86d"
68
68
  }
@@ -8,7 +8,7 @@ import CrudRefDisplay from "./CrudRefDisplay.vue";
8
8
  import {formatDate} from "@drax/common-front"
9
9
 
10
10
  const { t} = useI18n()
11
- const store = useCrudStore()
11
+
12
12
  const { filterIcon } = useFilterIcon()
13
13
 
14
14
  const props = defineProps({
@@ -18,6 +18,8 @@ const props = defineProps({
18
18
  }
19
19
  })
20
20
 
21
+ const store = useCrudStore(props.entity?.name)
22
+
21
23
  const activeFilters = computed<any[]>(() => {
22
24
  return store.filters
23
25
  .map((filter:any, index: any) => {
@@ -4,12 +4,16 @@ import { type PropType, type Ref} from "vue";
4
4
  import {ref, onBeforeMount} from "vue";
5
5
  import {getItemId} from "../helpers/getItemId"
6
6
  import type {IEntityCrud, IEntityCrudField} from "@drax/crud-share";
7
+ import CrudCreateOnTheFlyButton from "./buttons/CrudCreateOnTheFlyButton.vue";
7
8
 
8
9
  const valueModel = defineModel<string | string[]>({type: [String, Array], required: false})
9
10
 
10
11
  const {entity, multiple} = defineProps({
11
12
  entity: {type: Object as PropType<IEntityCrud|undefined>, required: true},
12
13
  field: {type: Object as PropType<IEntityCrudField>, required: true},
14
+ label: {type: String},
15
+ itemTitle: {type: [String], default: 'name'},
16
+ itemValue: {type: [String], default: '_id'},
13
17
  prependIcon: {type: String},
14
18
  prependInnerIcon: {type: String},
15
19
  appendIcon: {type: String},
@@ -19,15 +23,14 @@ const {entity, multiple} = defineProps({
19
23
  closableChips: {type: Boolean, default: true},
20
24
  readonly: {type: Boolean, default: false},
21
25
  clearable: {type: Boolean, default: true},
22
- label: {type: String},
26
+ noFilter: {type: Boolean, default: false},
23
27
  hint: {type: String},
24
28
  persistentHint: {type: Boolean, default: false},
25
- itemValue: {type: [String], default: '_id'},
26
- itemTitle: {type: [String], default: 'name'},
27
29
  rules: {type: Array as PropType<any>, default: () => []},
28
30
  errorMessages: {type: Array as PropType<string[]>, default: () => []},
29
31
  hideDetails: {type: Boolean, default: false},
30
32
  singleLine: {type: Boolean, default: false},
33
+ addOnTheFly: {type: Boolean, default: false},
31
34
  density: {type: String as PropType<'comfortable' | 'compact' | 'default'>, default: 'default'},
32
35
  variant: {type: String as PropType<'underlined' | 'outlined' | 'filled' | 'solo' | 'solo-inverted' | 'solo-filled' | 'plain'>, default: 'filled'},
33
36
  })
@@ -59,10 +62,7 @@ async function search(value: any) {
59
62
 
60
63
  }
61
64
 
62
- onBeforeMount(async () => {
63
- await search('')
64
- await checkIds()
65
- })
65
+
66
66
 
67
67
  async function checkIds(ids: Array<string> = []) {
68
68
  try{
@@ -90,6 +90,16 @@ async function checkIds(ids: Array<string> = []) {
90
90
  }
91
91
  }
92
92
 
93
+ onBeforeMount(async () => {
94
+ await search('')
95
+ await checkIds()
96
+ })
97
+
98
+ function onCreated(item: any) {
99
+ items.value.push(item)
100
+ valueModel.value = item._id
101
+ }
102
+
93
103
  defineEmits(['updateValue'])
94
104
 
95
105
  </script>
@@ -97,12 +107,12 @@ defineEmits(['updateValue'])
97
107
  <template>
98
108
 
99
109
  <v-select
100
- v-if="field.noFilter === true"
110
+ v-if="noFilter"
101
111
  v-model="valueModel"
102
112
  :label="label ? label : field.label"
103
- :hint="field.hint"
104
- :persistent-hint="field.persistentHint"
105
- :placeholder="field.label"
113
+ :placeholder="label ? label : field.label"
114
+ :hint="hint"
115
+ :persistent-hint="persistentHint"
106
116
  :items="items"
107
117
  :multiple="multiple"
108
118
  :chips="chips"
@@ -124,6 +134,11 @@ defineEmits(['updateValue'])
124
134
  :prepend-inner-icon="prependInnerIcon"
125
135
  :append-inner-icon="appendInnerIcon"
126
136
  >
137
+
138
+ <template v-if="addOnTheFly" v-slot:append>
139
+ <crud-create-on-the-fly-button :entity="entity" @created="onCreated"></crud-create-on-the-fly-button>
140
+ </template>
141
+
127
142
  <template v-slot:item="{ props: itemProps, item }">
128
143
  <v-list-item
129
144
  v-bind="itemProps"
@@ -151,9 +166,9 @@ defineEmits(['updateValue'])
151
166
  v-else
152
167
  v-model="valueModel"
153
168
  :label="label ? label : field.label"
154
- :hint="field.hint"
155
- :persistent-hint="field.persistentHint"
156
- :placeholder="field.label"
169
+ :placeholder="label ? label : field.label"
170
+ :hint="hint"
171
+ :persistent-hint="persistentHint"
157
172
  :items="items"
158
173
  :multiple="multiple"
159
174
  :chips="chips"
@@ -176,6 +191,11 @@ defineEmits(['updateValue'])
176
191
  :prepend-inner-icon="prependInnerIcon"
177
192
  :append-inner-icon="appendInnerIcon"
178
193
  >
194
+
195
+ <template v-if="addOnTheFly" v-slot:append>
196
+ <crud-create-on-the-fly-button :entity="entity" @created="onCreated"></crud-create-on-the-fly-button>
197
+ </template>
198
+
179
199
  <template v-slot:item="{ props: itemProps, item }">
180
200
  <v-list-item
181
201
  v-bind="itemProps"
@@ -8,7 +8,9 @@ const {t,te} = useI18n()
8
8
 
9
9
  const {operation,entity } = defineProps({
10
10
  entity: {type: Object as PropType<IEntityCrud>, required: true},
11
- operation: {type: String as PropType<IEntityCrudOperation>}
11
+ operation: {type: String as PropType<IEntityCrudOperation>},
12
+ fullscreen: {type: Boolean, default: undefined},
13
+ maxWidth: {type: String, default: undefined},
12
14
  })
13
15
 
14
16
  defineEmits(
@@ -32,8 +34,8 @@ const title = computed(() => {
32
34
  <template>
33
35
  <v-dialog v-model="dialog"
34
36
  :z-index="entity.dialogZindex"
35
- :fullscreen="entity.dialogFullscreen"
36
- :max-width="entity.dialogMaxWidth"
37
+ :fullscreen="fullscreen === undefined ? entity.dialogFullscreen : fullscreen"
38
+ :max-width="maxWidth === undefined ? entity.dialogMaxWidth : maxWidth"
37
39
  >
38
40
  <v-card>
39
41
  <v-toolbar>
@@ -21,7 +21,7 @@ const {onSubmit, onCancel, operation, error, form} = useCrud(entity)
21
21
 
22
22
  const emit = defineEmits(['created', 'updated', 'deleted', 'viewed', 'canceled'])
23
23
 
24
- const store = useCrudStore()
24
+ const store = useCrudStore(entity?.name)
25
25
 
26
26
  const formRef = ref()
27
27
 
@@ -14,7 +14,7 @@ const {t, te} = useI18n()
14
14
 
15
15
  const {hasPermission} = useAuth()
16
16
 
17
- const store = useCrudStore()
17
+
18
18
 
19
19
  const valueModel = defineModel<any>({type: [String, Number, Boolean, Object, Array], default: false})
20
20
 
@@ -40,6 +40,8 @@ const {index, entity, field, disableRules, parentField} = defineProps({
40
40
  },
41
41
  })
42
42
 
43
+ const store = useCrudStore(entity?.name)
44
+
43
45
 
44
46
  if (!field) {
45
47
  throw new Error("CrudFormField must be provided with a field object")
@@ -364,11 +366,13 @@ defineEmits(['updateValue'])
364
366
  v-if="field.type === 'ref'"
365
367
  :entity="entity.getRef(field.ref)"
366
368
  :field="field"
367
- :item-title="field?.refDisplay"
368
369
  v-model="valueModel"
370
+ @updateValue="$emit('updateValue')"
371
+ :item-title="field?.refDisplay"
369
372
  :label="label"
370
373
  :hint="field.hint"
371
374
  :persistent-hint="field.persistentHint"
375
+ :no-filter="field.noFilter"
372
376
  :error-messages="inputErrors"
373
377
  :rules="rules"
374
378
  :density="density"
@@ -377,11 +381,11 @@ defineEmits(['updateValue'])
377
381
  :clearable="clearable"
378
382
  :hide-details="hideDetails"
379
383
  :single-line="singleLine"
380
- @updateValue="$emit('updateValue')"
381
384
  :prepend-icon="prependIcon"
382
385
  :append-icon="appendIcon"
383
386
  :prepend-inner-icon="prependInnerIcon"
384
387
  :append-inner-icon="appendInnerIcon"
388
+ :add-on-the-fly="field?.addOnTheFly"
385
389
  />
386
390
 
387
391
  <v-card v-if="field.type === 'object'" class="mt-3" variant="flat" border>
@@ -476,6 +480,7 @@ defineEmits(['updateValue'])
476
480
  :label="label"
477
481
  :hint="field.hint"
478
482
  :persistent-hint="field.persistentHint"
483
+ :no-filter="field.noFilter"
479
484
  :rules="rules"
480
485
  :error-messages="inputErrors"
481
486
  :density="density"
@@ -488,6 +493,7 @@ defineEmits(['updateValue'])
488
493
  :append-icon="appendIcon"
489
494
  :prepend-inner-icon="prependInnerIcon"
490
495
  :append-inner-icon="appendInnerIcon"
496
+ :add-on-the-fly="field?.addOnTheFly"
491
497
  />
492
498
 
493
499
 
@@ -6,7 +6,7 @@ import {useI18n} from "vue-i18n";
6
6
  import {useCrudStore} from "../stores/UseCrudStore";
7
7
  import {useDisplay} from "vuetify"
8
8
 
9
- const store = useCrudStore()
9
+
10
10
  const {t, te} = useI18n()
11
11
  const valueModel = defineModel({type: Array, default: () => []});
12
12
 
@@ -24,6 +24,8 @@ const {field, entity} = defineProps({
24
24
  },
25
25
  })
26
26
 
27
+ const store = useCrudStore(entity?.name)
28
+
27
29
  function newItem() {
28
30
  return field.objectFields ? field.objectFields.reduce((acc, field) => ({
29
31
  ...acc,
@@ -0,0 +1,75 @@
1
+ <script setup lang="ts">
2
+ import {useI18n} from "vue-i18n";
3
+ import {defineProps, type PropType, ref} from "vue";
4
+ import type {IEntityCrud} from "@drax/crud-share";
5
+ import CrudForm from "../CrudForm.vue";
6
+ import CrudDialog from "../CrudDialog.vue";
7
+ import {useCrudStore} from "../../stores/UseCrudStore";
8
+ import {useCrud} from "../../composables/UseCrud";
9
+
10
+ const {t} = useI18n()
11
+
12
+ const dialog = ref(false)
13
+
14
+ const {entity} = defineProps({
15
+ entity: {type: Object as PropType<IEntityCrud>, required: true},
16
+ })
17
+
18
+ const store = useCrudStore(entity?.name)
19
+ store.$reset()
20
+ const {onCreate} = useCrud(entity)
21
+
22
+ function openDialog() {
23
+ onCreate()
24
+ dialog.value = true
25
+ }
26
+
27
+ function onCreated(item: any) {
28
+ dialog.value = false
29
+ emit('created', item)
30
+ }
31
+
32
+ function onCanceled() {
33
+ dialog.value = false
34
+ }
35
+
36
+ const emit = defineEmits(['created'])
37
+
38
+ </script>
39
+
40
+ <template>
41
+ <v-tooltip location="top">
42
+ <template v-slot:activator="{ props }">
43
+ <v-btn
44
+ v-bind="{ ...$attrs, ...props }"
45
+ icon="mdi-plus"
46
+ class="mr-1"
47
+ variant="text"
48
+ @click="openDialog"
49
+ >
50
+ </v-btn>
51
+ </template>
52
+ {{ t('action.create')}}
53
+ </v-tooltip>
54
+
55
+ <crud-dialog
56
+ v-model="dialog"
57
+ :entity="entity"
58
+ operation="create"
59
+ :fullscreen="false"
60
+ >
61
+ <crud-form
62
+ :entity="entity"
63
+ @created="onCreated"
64
+ @canceled="onCanceled"
65
+
66
+ >
67
+ </crud-form>
68
+
69
+ </crud-dialog>
70
+
71
+ </template>
72
+
73
+ <style scoped>
74
+
75
+ </style>
@@ -6,7 +6,7 @@ import {useI18n} from "vue-i18n";
6
6
 
7
7
  export function useCrud(entity: IEntityCrud) {
8
8
 
9
- const store = useCrudStore()
9
+ const store = useCrudStore(entity?.name)
10
10
 
11
11
  const {t: $t} = useI18n()
12
12
 
@@ -8,7 +8,7 @@ import { useCrudStore } from '../stores/UseCrudStore'
8
8
  export function useCrudColumns(entity: IEntityCrud) {
9
9
  const { hasPermission } = useAuth()
10
10
  const { t, te } = useI18n()
11
- const crudStore = useCrudStore()
11
+ const crudStore = useCrudStore(entity?.name)
12
12
 
13
13
  // Clave única para localStorage basada en el nombre de la entidad
14
14
  const storageKey = `crud_visible_columns_${entity.name.toLowerCase()}`
@@ -42,22 +42,22 @@ export function useCrudColumns(entity: IEntityCrud) {
42
42
 
43
43
  // Intentar cargar desde localStorage primero
44
44
  const storedColumns = loadColumnsFromStorage()
45
-
45
+
46
46
  let initialColumns: string[]
47
-
47
+
48
48
  if (storedColumns) {
49
49
  // Filtrar columnas almacenadas para asegurar que aún existen y tienen permisos
50
50
  initialColumns = storedColumns.filter(key => availableHeaders.includes(key))
51
-
51
+
52
52
  // Si no quedaron columnas válidas, usar las predeterminadas
53
53
  if (initialColumns.length === 0) {
54
- initialColumns = entity.selectedHeaders?.filter(key =>
54
+ initialColumns = entity.selectedHeaders?.filter(key =>
55
55
  availableHeaders.includes(key)
56
56
  ) || availableHeaders
57
57
  }
58
58
  } else {
59
59
  // Si no hay columnas guardadas, usar selectedHeaders o todas las disponibles
60
- initialColumns = entity.selectedHeaders?.filter(key =>
60
+ initialColumns = entity.selectedHeaders?.filter(key =>
61
61
  availableHeaders.includes(key)
62
62
  ) || availableHeaders
63
63
  }
@@ -80,15 +80,15 @@ export function useCrudColumns(entity: IEntityCrud) {
80
80
  .filter(header => !header.permission || hasPermission(header.permission))
81
81
  .map(header => ({
82
82
  ...header,
83
- title: te(`${entity.name.toLowerCase()}.field.${header.title}`)
84
- ? t(`${entity.name.toLowerCase()}.field.${header.title}`)
83
+ title: te(`${entity.name.toLowerCase()}.field.${header.title}`)
84
+ ? t(`${entity.name.toLowerCase()}.field.${header.title}`)
85
85
  : header.title
86
86
  }))
87
87
  })
88
88
 
89
89
  // Headers filtrados por columnas visibles
90
90
  const filteredHeaders = computed<IEntityCrudHeader[]>(() => {
91
- const filtered = translatedHeaders.value.filter(header =>
91
+ const filtered = translatedHeaders.value.filter(header =>
92
92
  visibleColumns.value.includes(header.key)
93
93
  )
94
94
  const actions = entity.actionHeaders.map(header => ({
@@ -111,19 +111,19 @@ export function useCrudColumns(entity: IEntityCrud) {
111
111
  const toggleColumn = (columnKey: string) => {
112
112
  const currentColumns = [...visibleColumns.value]
113
113
  const index = currentColumns.indexOf(columnKey)
114
-
114
+
115
115
  if (index > -1) {
116
116
  currentColumns.splice(index, 1)
117
117
  } else {
118
118
  currentColumns.push(columnKey)
119
119
  }
120
-
120
+
121
121
  crudStore.setVisibleColumns(currentColumns)
122
122
  // Guardar cambios en localStorage
123
123
  saveColumnsToStorage(currentColumns)
124
124
  }
125
125
 
126
- const allSelected = computed(() =>
126
+ const allSelected = computed(() =>
127
127
  availableColumns.value.every(col => col.visible)
128
128
  )
129
129
 
@@ -150,7 +150,7 @@ export function useCrudColumns(entity: IEntityCrud) {
150
150
  .filter(header => !header.permission || hasPermission(header.permission))
151
151
  .map(header => header.key)
152
152
 
153
- const defaultColumns = entity.selectedHeaders?.filter(key =>
153
+ const defaultColumns = entity.selectedHeaders?.filter(key =>
154
154
  availableHeaders.includes(key)
155
155
  ) || availableHeaders
156
156
 
@@ -8,7 +8,7 @@ import {useCrudStore} from '../stores/UseCrudStore'
8
8
  export const useCrudGroupBy = (entity: IEntityCrud) => {
9
9
  const { t, te } = useI18n()
10
10
  const groupBystore = useGroupByStore()
11
- const crudStore = useCrudStore()
11
+ const crudStore = useCrudStore(entity?.name)
12
12
  const entityName = entity.name.toLowerCase()
13
13
 
14
14
  const availableFields = computed<IEntityCrudField[]>(() => {
@@ -1,10 +1,11 @@
1
1
  import {useCrudStore} from "../stores/UseCrudStore";
2
2
  import {useI18n} from "vue-i18n";
3
3
  import {computed} from "vue";
4
+ import type {IEntityCrud} from "@drax/crud-share";
4
5
 
5
- export function useInputErrorI18n() {
6
+ export function useInputErrorI18n(entity: IEntityCrud) {
6
7
 
7
- const store = useCrudStore()
8
+ const store = useCrudStore(entity?.name)
8
9
 
9
10
  const {t, te} = useI18n()
10
11
 
@@ -1,7 +1,7 @@
1
1
  import {defineStore} from "pinia";
2
2
  import type {IEntityCrudOperation, IDraxFieldFilter} from "@drax/crud-share";
3
3
 
4
- export const useCrudStore = defineStore('CrudStore', {
4
+ export const useCrudStore = (id: string = 'entity') => defineStore('CrudStore'+id, {
5
5
  state: () => (
6
6
  {
7
7
  operation: null as IEntityCrudOperation,
@@ -142,4 +142,4 @@ export const useCrudStore = defineStore('CrudStore', {
142
142
  }
143
143
  }
144
144
 
145
- })
145
+ })()