@drax/audit-vue 0.38.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 ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@drax/audit-vue",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "0.38.0",
7
+ "type": "module",
8
+ "main": "./src/index.ts",
9
+ "module": "./src/index.ts",
10
+ "types": "./src/index.ts",
11
+ "files": [
12
+ "src"
13
+ ],
14
+ "scripts": {
15
+ "dev": "vite",
16
+ "build": "run-p type-check \"build-only {@}\" --",
17
+ "preview": "vite preview",
18
+ "test:unit": "vitest",
19
+ "test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'",
20
+ "test:e2e:dev": "start-server-and-test 'vite dev --port 4173' http://localhost:4173 'cypress open --e2e'",
21
+ "build-only": "vite build",
22
+ "type-check": "vue-tsc --build --force",
23
+ "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
24
+ "format": "prettier --write src/"
25
+ },
26
+ "dependencies": {
27
+ "@drax/crud-front": "^0.38.0",
28
+ "@drax/crud-share": "^0.38.0"
29
+ },
30
+ "peerDependencies": {
31
+ "pinia": "^2.2.2",
32
+ "vue": "^3.5.7",
33
+ "vue-i18n": "^9.14.0",
34
+ "vuetify": "^3.7.2"
35
+ },
36
+ "devDependencies": {
37
+ "@rushstack/eslint-patch": "^1.8.0",
38
+ "@tsconfig/node20": "^20.1.4",
39
+ "@types/jsdom": "^21.1.7",
40
+ "@types/node": "^20.12.5",
41
+ "@vitejs/plugin-vue": "^5.0.4",
42
+ "@vue/eslint-config-prettier": "^9.0.0",
43
+ "@vue/eslint-config-typescript": "^13.0.0",
44
+ "@vue/test-utils": "^2.4.5",
45
+ "@vue/tsconfig": "^0.5.1",
46
+ "cypress": "^13.7.2",
47
+ "eslint": "^8.57.0",
48
+ "eslint-plugin-cypress": "^2.15.1",
49
+ "eslint-plugin-vue": "^9.23.0",
50
+ "jsdom": "^24.0.0",
51
+ "npm-run-all2": "^6.1.2",
52
+ "pinia": "^2.1.7",
53
+ "pinia-plugin-persistedstate": "^3.2.1",
54
+ "prettier": "^3.2.5",
55
+ "start-server-and-test": "^2.0.3",
56
+ "typescript": "5.6.3",
57
+ "vite": "^5.4.3",
58
+ "vite-plugin-css-injected-by-js": "^3.5.1",
59
+ "vite-plugin-dts": "^3.9.1",
60
+ "vitest": "^1.4.0",
61
+ "vue": "^3.5.3",
62
+ "vue-tsc": "^2.0.11",
63
+ "vuetify": "^3.7.1"
64
+ },
65
+ "gitHead": "43c90f3c12165e7527edefbc80dd327a59236dd5"
66
+ }
@@ -0,0 +1,380 @@
1
+
2
+ <script setup lang="ts">
3
+ import { computed } from 'vue'
4
+ import type { IAudit } from '@drax/audit-share'
5
+
6
+ interface Props {
7
+ audit: IAudit
8
+ }
9
+
10
+ const props = defineProps<Props>()
11
+
12
+ const actionColor = computed(() => {
13
+ const actionMap: Record<string, string> = {
14
+ 'CREATE': 'success',
15
+ 'UPDATE': 'warning',
16
+ 'DELETE': 'error',
17
+ 'READ': 'info',
18
+ 'EXPORT': 'primary'
19
+ }
20
+ return actionMap[props.audit.action] || 'secondary'
21
+ })
22
+
23
+ const actionIcon = computed(() => {
24
+ const iconMap: Record<string, string> = {
25
+ 'CREATE': 'mdi-plus-circle',
26
+ 'UPDATE': 'mdi-pencil-circle',
27
+ 'DELETE': 'mdi-delete-circle',
28
+ 'READ': 'mdi-eye-circle',
29
+ 'EXPORT': 'mdi-download-circle'
30
+ }
31
+ return iconMap[props.audit.action] || 'mdi-information-circle'
32
+ })
33
+
34
+ const formattedDate = computed(() => {
35
+ if (!props.audit.createdAt) return 'N/A'
36
+ return new Date(props.audit.createdAt).toLocaleString('es-ES', {
37
+ year: 'numeric',
38
+ month: '2-digit',
39
+ day: '2-digit',
40
+ hour: '2-digit',
41
+ minute: '2-digit',
42
+ second: '2-digit'
43
+ })
44
+ })
45
+
46
+ const hasChanges = computed(() => {
47
+ return props.audit.changes && props.audit.changes.length > 0
48
+ })
49
+
50
+ const copyToClipboard = (text: string) => {
51
+ navigator.clipboard.writeText(text)
52
+ }
53
+ </script>
54
+
55
+ <template>
56
+ <v-card class="audit-view-card" elevation="2">
57
+ <!-- Header con acción y fecha -->
58
+ <v-card-title class="d-flex align-center pa-4 bg-gradient">
59
+ <v-icon :color="actionColor" size="32" class="mr-3">
60
+ {{ actionIcon }}
61
+ </v-icon>
62
+ <div class="flex-grow-1">
63
+ <div class="text-h6 font-weight-bold">
64
+ {{ audit.action }}
65
+ </div>
66
+ <div class="text-caption text-medium-emphasis">
67
+ {{ formattedDate }}
68
+ </div>
69
+ </div>
70
+ <v-chip :color="actionColor" variant="flat" size="small" class="font-weight-bold">
71
+ {{ audit.entity }}
72
+ </v-chip>
73
+ </v-card-title>
74
+
75
+ <v-divider />
76
+
77
+ <v-card-text class="pa-6">
78
+ <!-- Información General -->
79
+ <div class="mb-8">
80
+ <div class="section-header mb-4">
81
+ <v-icon color="primary" class="mr-2">mdi-information</v-icon>
82
+ <span class="text-subtitle-1 font-weight-bold">Información General</span>
83
+ </div>
84
+ <v-card variant="outlined" class="pa-4">
85
+ <div class="info-row mb-4">
86
+ <span class="info-label">Acción:</span>
87
+ <v-chip :color="actionColor" variant="tonal" size="small" class="ml-2">
88
+ {{ audit.action }}
89
+ </v-chip>
90
+ </div>
91
+ <v-divider class="my-3" />
92
+ <div class="info-row">
93
+ <span class="info-label">Entidad:</span>
94
+ <span class="info-value">{{ audit.entity }}</span>
95
+ </div>
96
+ </v-card>
97
+ </div>
98
+
99
+ <!-- Información del Usuario -->
100
+ <div class="mb-8">
101
+ <div class="section-header mb-4">
102
+ <v-icon color="primary" class="mr-2">mdi-account-circle</v-icon>
103
+ <span class="text-subtitle-1 font-weight-bold">Usuario</span>
104
+ </div>
105
+ <v-card variant="outlined" class="pa-4">
106
+ <div class="info-row mb-4">
107
+ <span class="info-label">Nombre de Usuario:</span>
108
+ <span class="info-value">{{ audit.user.username }}</span>
109
+ </div>
110
+ <v-divider class="my-3" />
111
+ <div class="info-row mb-4">
112
+ <span class="info-label">Rol:</span>
113
+ <v-chip size="small" color="primary" variant="tonal" class="ml-2">
114
+ {{ audit.user.rolName }}
115
+ </v-chip>
116
+ </div>
117
+ <v-divider class="my-3" />
118
+ <div class="info-row">
119
+ <span class="info-label">ID de Usuario:</span>
120
+ <div class="d-flex align-center gap-2 ml-2">
121
+ <span class="info-value font-monospace text-caption">{{ audit.user.id }}</span>
122
+ <v-btn
123
+ icon
124
+ size="x-small"
125
+ variant="text"
126
+ @click="copyToClipboard(audit.user.id)"
127
+ >
128
+ <v-icon size="small">mdi-content-copy</v-icon>
129
+ </v-btn>
130
+ </div>
131
+ </div>
132
+ </v-card>
133
+ </div>
134
+
135
+ <!-- Información de Conexión -->
136
+ <div class="mb-8">
137
+ <div class="section-header mb-4">
138
+ <v-icon color="info" class="mr-2">mdi-network</v-icon>
139
+ <span class="text-subtitle-1 font-weight-bold">Información de Conexión</span>
140
+ </div>
141
+ <v-card variant="outlined" class="pa-4">
142
+ <div class="info-row mb-4">
143
+ <span class="info-label">
144
+ <v-icon size="x-small" class="mr-1">mdi-ip</v-icon>
145
+ Dirección IP:
146
+ </span>
147
+ <div class="d-flex align-center gap-2 ml-2">
148
+ <v-chip size="small" variant="tonal" color="info">
149
+ {{ audit.ip }}
150
+ </v-chip>
151
+ <v-btn
152
+ icon
153
+ size="x-small"
154
+ variant="text"
155
+ @click="copyToClipboard(audit.ip)"
156
+ >
157
+ <v-icon size="small">mdi-content-copy</v-icon>
158
+ </v-btn>
159
+ </div>
160
+ </div>
161
+ <v-divider class="my-3" />
162
+ <div class="info-row">
163
+ <span class="info-label">
164
+ <v-icon size="x-small" class="mr-1">mdi-web</v-icon>
165
+ User Agent:
166
+ </span>
167
+ <span class="info-value text-caption">{{ audit.userAgent }}</span>
168
+ </div>
169
+ </v-card>
170
+ </div>
171
+
172
+ <!-- Cambios Realizados -->
173
+ <div v-if="hasChanges" class="mb-8">
174
+ <div class="section-header mb-4">
175
+ <v-icon color="warning" class="mr-2">mdi-file-document-edit</v-icon>
176
+ <span class="text-subtitle-1 font-weight-bold">Cambios Realizados</span>
177
+ <v-chip size="x-small" color="warning" variant="tonal" class="ml-2">
178
+ {{ audit.changes?.length }} cambios
179
+ </v-chip>
180
+ </div>
181
+ <v-card variant="outlined" class="overflow-hidden">
182
+ <v-list lines="three" class="pa-0">
183
+ <template v-for="(change, index) in audit.changes" :key="index">
184
+ <v-list-item class="change-item">
185
+ <template #prepend>
186
+ <v-avatar color="warning" size="40" class="font-weight-bold">
187
+ <v-icon size="small">mdi-swap-horizontal</v-icon>
188
+ </v-avatar>
189
+ </template>
190
+ <div class="w-100">
191
+ <v-list-item-title class="font-weight-bold text-base mb-3">
192
+ Campo: {{ change.field }}
193
+ </v-list-item-title>
194
+ <div v-if="change.old" class="mb-2">
195
+ <span class="info-label">Valor Anterior:</span>
196
+ <v-chip
197
+ size="small"
198
+ color="error"
199
+ variant="tonal"
200
+ class="font-monospace ml-2 mt-1"
201
+ >
202
+ <v-icon start size="x-small">mdi-minus</v-icon>
203
+ {{ change.old }}
204
+ </v-chip>
205
+ </div>
206
+ <div v-if="change.new">
207
+ <span class="info-label">Valor Nuevo:</span>
208
+ <v-chip
209
+ size="small"
210
+ color="success"
211
+ variant="tonal"
212
+ class="font-monospace ml-2 mt-1"
213
+ >
214
+ <v-icon start size="x-small">mdi-plus</v-icon>
215
+ {{ change.new }}
216
+ </v-chip>
217
+ </div>
218
+ </div>
219
+ </v-list-item>
220
+ <v-divider v-if="index < audit.changes!.length - 1" />
221
+ </template>
222
+ </v-list>
223
+ </v-card>
224
+ </div>
225
+
226
+ <!-- Detalles Adicionales -->
227
+ <div v-if="audit.detail" class="mb-8">
228
+ <div class="section-header mb-4">
229
+ <v-icon color="info" class="mr-2">mdi-text-box</v-icon>
230
+ <span class="text-subtitle-1 font-weight-bold">Detalles Adicionales</span>
231
+ </div>
232
+ <v-card variant="outlined" class="pa-4">
233
+ <pre class="detail-text">{{ audit.detail }}</pre>
234
+ </v-card>
235
+ </div>
236
+
237
+ <!-- Información del Tenant -->
238
+ <div v-if="audit.tenant" class="mb-8">
239
+ <div class="section-header mb-4">
240
+ <v-icon color="secondary" class="mr-2">mdi-domain</v-icon>
241
+ <span class="text-subtitle-1 font-weight-bold">Tenant</span>
242
+ </div>
243
+ <v-card variant="outlined" class="pa-4">
244
+ <div class="info-row mb-4">
245
+ <span class="info-label">Nombre del Tenant:</span>
246
+ <span class="info-value">{{ audit.tenant.name }}</span>
247
+ </div>
248
+ <v-divider class="my-3" />
249
+ <div class="info-row">
250
+ <span class="info-label">ID del Tenant:</span>
251
+ <div class="d-flex align-center gap-2 ml-2">
252
+ <span class="info-value text-caption font-monospace">{{ audit.tenant.id }}</span>
253
+ <v-btn
254
+ icon
255
+ size="x-small"
256
+ variant="text"
257
+ @click="copyToClipboard(audit.tenant.id)"
258
+ >
259
+ <v-icon size="small">mdi-content-copy</v-icon>
260
+ </v-btn>
261
+ </div>
262
+ </div>
263
+ </v-card>
264
+ </div>
265
+
266
+ <!-- IDs de Sesión y Request -->
267
+ <div>
268
+ <div class="section-header mb-4">
269
+ <v-icon color="grey" class="mr-2">mdi-identifier</v-icon>
270
+ <span class="text-subtitle-1 font-weight-bold">Identificadores de Sesión</span>
271
+ </div>
272
+ <v-card variant="outlined" class="pa-4">
273
+ <div class="info-row mb-4">
274
+ <span class="info-label">ID de Auditoría:</span>
275
+ <div class="d-flex align-center gap-2 ml-2">
276
+ <span class="info-value text-caption font-monospace">{{ audit._id }}</span>
277
+ <v-btn
278
+ icon
279
+ size="x-small"
280
+ variant="text"
281
+ @click="copyToClipboard(audit._id)"
282
+ >
283
+ <v-icon size="small">mdi-content-copy</v-icon>
284
+ </v-btn>
285
+ </div>
286
+ </div>
287
+ <v-divider class="my-3" />
288
+ <div v-if="audit.sessionId" class="info-row mb-4">
289
+ <span class="info-label">ID de Sesión:</span>
290
+ <div class="d-flex align-center gap-2 ml-2">
291
+ <span class="info-value text-caption font-monospace">{{ audit.sessionId }}</span>
292
+ <v-btn
293
+ icon
294
+ size="x-small"
295
+ variant="text"
296
+ @click="copyToClipboard(audit.sessionId)"
297
+ >
298
+ <v-icon size="small">mdi-content-copy</v-icon>
299
+ </v-btn>
300
+ </div>
301
+ </div>
302
+ <v-divider class="my-3" />
303
+ <div v-if="audit.requestId" class="info-row">
304
+ <span class="info-label">ID de Petición:</span>
305
+ <div class="d-flex align-center gap-2 ml-2">
306
+ <span class="info-value text-caption font-monospace">{{ audit.requestId }}</span>
307
+ <v-btn
308
+ icon
309
+ size="x-small"
310
+ variant="text"
311
+ @click="copyToClipboard(audit.requestId)"
312
+ >
313
+ <v-icon size="small">mdi-content-copy</v-icon>
314
+ </v-btn>
315
+ </div>
316
+ </div>
317
+ </v-card>
318
+ </div>
319
+ </v-card-text>
320
+ </v-card>
321
+ </template>
322
+
323
+ <style scoped>
324
+ .audit-view-card {
325
+ border-radius: 12px;
326
+ overflow: hidden;
327
+ transition: all 0.3s ease;
328
+ }
329
+
330
+ .audit-view-card:hover {
331
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12) !important;
332
+ }
333
+
334
+ .bg-gradient {
335
+ background: linear-gradient(135deg, rgb(var(--v-theme-surface-variant)) 0%, rgb(var(--v-theme-surface)) 100%);
336
+ }
337
+
338
+ .section-header {
339
+ display: flex;
340
+ align-items: center;
341
+ padding-bottom: 8px;
342
+ border-bottom: 2px solid rgba(var(--v-theme-primary), 0.2);
343
+ }
344
+
345
+ .info-row {
346
+ display: flex;
347
+ flex-direction: column;
348
+ gap: 6px;
349
+ }
350
+
351
+ .info-label {
352
+ font-size: 0.875rem;
353
+ font-weight: 700;
354
+ color: rgb(var(--v-theme-on-surface-variant));
355
+ text-transform: uppercase;
356
+ }
357
+
358
+ .info-value {
359
+ font-size: 0.875rem;
360
+ color: rgb(var(--v-theme-on-surface));
361
+ }
362
+
363
+ .detail-text {
364
+ white-space: pre-wrap;
365
+ word-break: break-word;
366
+ margin: 0;
367
+ padding: 0;
368
+ font-family: 'Courier New', monospace;
369
+ font-size: 0.875rem;
370
+ color: rgb(var(--v-theme-on-surface));
371
+ }
372
+
373
+ .change-item {
374
+ transition: background-color 0.2s ease;
375
+ }
376
+
377
+ .change-item:hover {
378
+ background-color: rgba(var(--v-theme-surface-variant), 0.5);
379
+ }
380
+ </style>
@@ -0,0 +1,204 @@
1
+ import {EntityCrud} from "@drax/crud-vue";
2
+ import type {
3
+ IDraxCrudProvider,
4
+ IEntityCrud,
5
+ IEntityCrudField,
6
+ IEntityCrudFilter,
7
+ IEntityCrudHeader,
8
+ IEntityCrudPermissions,
9
+ IEntityCrudRefs,
10
+ IEntityCrudRules
11
+ } from "@drax/crud-share";
12
+ import {AuditProvider} from "@drax/audit-front";
13
+
14
+ //Import EntityCrud Refs
15
+
16
+ class AuditCrud extends EntityCrud implements IEntityCrud {
17
+
18
+ static singleton: AuditCrud
19
+
20
+ constructor() {
21
+ super();
22
+ this.name = 'Audit'
23
+ }
24
+
25
+ static get instance(): AuditCrud {
26
+ if (!AuditCrud.singleton) {
27
+ AuditCrud.singleton = new AuditCrud()
28
+ }
29
+ return AuditCrud.singleton
30
+ }
31
+
32
+ get permissions(): IEntityCrudPermissions {
33
+ return {
34
+ manage: 'audit:manage',
35
+ view: 'audit:view',
36
+ create: 'audit:create',
37
+ update: 'audit:update',
38
+ delete: 'audit:delete'
39
+ }
40
+ }
41
+
42
+ get headers(): IEntityCrudHeader[] {
43
+ return [
44
+ {title: 'createdAt',key:'createdAt', align: 'start'},
45
+ {title: 'entity',key:'entity', align: 'start'},
46
+ {title: 'user',key:'user', align: 'start'},
47
+ {title: 'action',key:'action', align: 'start'},
48
+ {title: 'ip',key:'ip', align: 'start'},
49
+ {title: 'userAgent',key:'userAgent', align: 'start'},
50
+ {title: 'changes',key:'changes', align: 'start'},
51
+ {title: 'sessionId',key:'sessionId', align: 'start'},
52
+ {title: 'requestId',key:'requestId', align: 'start'},
53
+ {title: 'detail',key:'detail', align: 'start'},
54
+ {title: 'tenant',key:'tenant', align: 'start'}
55
+ ]
56
+ }
57
+
58
+ get selectedHeaders(): string[] {
59
+ return this.headers
60
+ .filter(header => ['detail','sessionId','requestId','userAgent','ip'].includes(header.key))
61
+ .map(header => header.key)
62
+
63
+ }
64
+
65
+ get actionHeaders(): IEntityCrudHeader[] {
66
+ return [
67
+ {
68
+ title: 'action.actions',
69
+ key: 'actions',
70
+ sortable: false,
71
+ align: 'center',
72
+ minWidth: '190px'
73
+ },
74
+ ]
75
+ }
76
+
77
+ get provider(): IDraxCrudProvider<any, any, any> {
78
+ return AuditProvider.instance
79
+ }
80
+
81
+ get refs(): IEntityCrudRefs {
82
+ return {}
83
+ }
84
+
85
+ get rules(): IEntityCrudRules {
86
+ return {
87
+ entity: [(v: any) => !!v || 'validation.required'],
88
+ user: [(v: any) => !!v || 'validation.required'],
89
+ action: [(v: any) => !!v || 'validation.required'],
90
+ ip: [(v: any) => !!v || 'validation.required'],
91
+ userAgent: [(v: any) => !!v || 'validation.required'],
92
+ changes: [],
93
+ sessionId: [],
94
+ requestId: [],
95
+ detail: [],
96
+ tenant: []
97
+ }
98
+ }
99
+
100
+ get fields(): IEntityCrudField[] {
101
+ return [
102
+ {name: 'entity', type: 'string', label: 'entity', default: ''},
103
+ {
104
+ name: 'user',
105
+ type: 'object',
106
+ label: 'user',
107
+ default: {"id": "''", "username": "''", "rolName": "''"},
108
+ objectFields: [{name: 'id', type: 'string', label: 'id', default: ''},
109
+ {name: 'username', type: 'string', label: 'username', default: ''},
110
+ {name: 'rolName', type: 'string', label: 'rolName', default: ''}]
111
+ },
112
+ {name: 'action', type: 'string', label: 'action', default: ''},
113
+ {name: 'ip', type: 'string', label: 'ip', default: ''},
114
+ {name: 'userAgent', type: 'string', label: 'userAgent', default: ''},
115
+ {
116
+ name: 'changes',
117
+ type: 'array.object',
118
+ label: 'changes',
119
+ default: [],
120
+ objectFields: [{name: 'field', type: 'string', label: 'field', default: ''},
121
+ {name: 'old', type: 'string', label: 'old', default: ''},
122
+ {name: 'new', type: 'string', label: 'new', default: ''}]
123
+ },
124
+ {name: 'sessionId', type: 'string', label: 'sessionId', default: ''},
125
+ {name: 'requestId', type: 'string', label: 'requestId', default: ''},
126
+ {name: 'detail', type: 'longString', label: 'detail', default: ''},
127
+ {
128
+ name: 'tenant',
129
+ type: 'object',
130
+ label: 'tenant',
131
+ default: {"id": "''", "name": "''"},
132
+ objectFields: [{name: 'id', type: 'string', label: 'id', default: ''},
133
+ {name: 'name', type: 'string', label: 'name', default: ''}]
134
+ }
135
+ ]
136
+ }
137
+
138
+ get filters(): IEntityCrudFilter[] {
139
+ return [
140
+ //{name: '_id', type: 'string', label: 'ID', default: '', operator: 'eq' },
141
+ ]
142
+ }
143
+
144
+ get isViewable() {
145
+ return true
146
+ }
147
+
148
+ get isEditable() {
149
+ return false
150
+ }
151
+
152
+ get isCreatable() {
153
+ return false
154
+ }
155
+
156
+ get isDeletable() {
157
+ return false
158
+ }
159
+
160
+ get isExportable() {
161
+ return true
162
+ }
163
+
164
+ get exportFormats() {
165
+ return ['CSV', 'JSON']
166
+ }
167
+
168
+ get exportHeaders() {
169
+ return ['_id']
170
+ }
171
+
172
+ get isImportable() {
173
+ return false
174
+ }
175
+
176
+ get isColumnSelectable() {
177
+ return true
178
+ }
179
+
180
+ get isGroupable() {
181
+ return true
182
+ }
183
+
184
+ get importFormats() {
185
+ return ['CSV', 'JSON']
186
+ }
187
+
188
+ get dialogFullscreen() {
189
+ return false
190
+ }
191
+
192
+ get tabs() {
193
+ return []
194
+ }
195
+
196
+ get menus() {
197
+ return []
198
+ }
199
+
200
+
201
+ }
202
+
203
+ export default AuditCrud
204
+
package/src/index.ts ADDED
@@ -0,0 +1,17 @@
1
+ import AuditRoutes from './routes/index'
2
+ import AuditCrudPage from './pages/crud/AuditCrudPage.vue'
3
+ import AuditView from './components/AuditView.vue'
4
+ import AuditCrud from './cruds/AuditCrud'
5
+
6
+
7
+ export {
8
+ //ROUTES
9
+ AuditRoutes,
10
+ //PAGES
11
+ AuditCrudPage,
12
+ //COMPONENTS
13
+ AuditView,
14
+ //CRUD
15
+ AuditCrud,
16
+ //I18N
17
+ }
@@ -0,0 +1,28 @@
1
+
2
+ <script setup lang="ts">
3
+ import AuditCrud from '../../cruds/AuditCrud'
4
+ import {Crud, useCrudStore} from "@drax/crud-vue";
5
+ import {formatDateTime} from "@drax/common-front"
6
+ import AuditView from "../../components/AuditView.vue";
7
+
8
+ const store = useCrudStore();
9
+
10
+ </script>
11
+
12
+ <template>
13
+ <crud :entity="AuditCrud.instance">
14
+
15
+ <template v-slot:item.createdAt="{value}">
16
+ {{ formatDateTime(value) }}
17
+ </template>
18
+
19
+ <template v-slot:form>
20
+ <audit-view :audit="store.form"></audit-view>
21
+ </template>
22
+ </crud>
23
+ </template>
24
+
25
+ <style scoped>
26
+
27
+ </style>
28
+
@@ -0,0 +1,18 @@
1
+
2
+ import AuditCrudPage from "../pages/crud/AuditCrudPage.vue";
3
+
4
+
5
+ const AuditCrudRoute = [
6
+ {
7
+ name: 'AuditCrudPage',
8
+ path: '/crud/audit',
9
+ component: AuditCrudPage,
10
+ meta: {
11
+ auth: true,
12
+ permission: 'audit:manage',
13
+ }
14
+ },
15
+ ]
16
+
17
+ export default AuditCrudRoute
18
+ export { AuditCrudRoute }
@@ -0,0 +1,8 @@
1
+ import {AuditCrudRoute} from "./AuditCrudRoute"
2
+
3
+
4
+ const index = [
5
+ ...AuditCrudRoute
6
+ ]
7
+
8
+ export default index