|
|
@@ -3,8 +3,7 @@ A data table for the parameters page
|
|
|
-->
|
|
|
<template>
|
|
|
<div class="container">
|
|
|
- <UiLoadingPanel v-if="pending" />
|
|
|
- <v-table v-else>
|
|
|
+ <v-table>
|
|
|
<thead>
|
|
|
<tr>
|
|
|
<td v-for="col in columns">
|
|
|
@@ -19,25 +18,28 @@ A data table for the parameters page
|
|
|
:key="i"
|
|
|
>
|
|
|
<td
|
|
|
- v-for="col in columns"
|
|
|
+ v-for="col in columnsDefinitions"
|
|
|
class="cycle-editable-cell"
|
|
|
>
|
|
|
{{ item[col.property] }}
|
|
|
</td>
|
|
|
|
|
|
<td class="d-flex flex-row actions-cell">
|
|
|
- <v-btn
|
|
|
- v-if="actions.includes(TABLE_ACTION.EDIT)"
|
|
|
- :flat="true"
|
|
|
- icon="fa fa-pen"
|
|
|
- class="mr-3"
|
|
|
- @click="goToEditPage(item.id as number)"
|
|
|
- />
|
|
|
- <UiButtonDelete
|
|
|
- v-if="actions.includes(TABLE_ACTION.DELETE)"
|
|
|
- :entity="item"
|
|
|
- :flat="true"
|
|
|
- />
|
|
|
+ <slot name="actions" :item="item">
|
|
|
+ <v-btn
|
|
|
+ v-if="actions.includes(TABLE_ACTION.EDIT)"
|
|
|
+ :flat="true"
|
|
|
+ icon="fa fa-pen"
|
|
|
+ class="mr-3"
|
|
|
+ @click="emit('editClicked', item)"
|
|
|
+ />
|
|
|
+ <v-btn
|
|
|
+ v-if="actions.includes(TABLE_ACTION.DELETE)"
|
|
|
+ :flat="true"
|
|
|
+ icon="fas fa-trash"
|
|
|
+ @click="emit('deleteClicked', item)"
|
|
|
+ />
|
|
|
+ </slot>
|
|
|
</td>
|
|
|
</tr>
|
|
|
</tbody>
|
|
|
@@ -55,7 +57,7 @@ A data table for the parameters page
|
|
|
:flat="true"
|
|
|
prepend-icon="fa fa-plus"
|
|
|
class="theme-primary mt-4"
|
|
|
- @click="goToCreatePage"
|
|
|
+ @click="emit('addClicked')"
|
|
|
>
|
|
|
{{ i18n.t('add') }}
|
|
|
</v-btn>
|
|
|
@@ -66,42 +68,15 @@ A data table for the parameters page
|
|
|
<script setup lang="ts">
|
|
|
import {TABLE_ACTION} from '~/types/enum/enums';
|
|
|
import UrlUtils from '~/services/utils/urlUtils';
|
|
|
-import type ApiResource from '~/models/ApiResource';
|
|
|
-import {useEntityFetch} from '~/composables/data/useEntityFetch';
|
|
|
-import type {AssociativeArray} from '~/types/data';
|
|
|
-
|
|
|
-interface ColumnDefinition {
|
|
|
- /**
|
|
|
- * The entity's property to display in this column
|
|
|
- */
|
|
|
- property: string,
|
|
|
- /**
|
|
|
- * Label of the column.
|
|
|
- * If not provided, a translation of the property's name will be looked for.
|
|
|
- * If none is found, the property's name will be displayed as it is.
|
|
|
- */
|
|
|
- label?: string
|
|
|
-}
|
|
|
+import type {ColumnDefinition} from '~/types/interfaces';
|
|
|
|
|
|
const props = defineProps({
|
|
|
/**
|
|
|
- * The model whom entities shall be to fetch
|
|
|
+ * Array of objects to display in the table
|
|
|
*/
|
|
|
- model: {
|
|
|
- type: Object as PropType<typeof ApiResource>,
|
|
|
- required: true
|
|
|
- },
|
|
|
- /**
|
|
|
- * The base URL for the edit / create pages
|
|
|
- * The resulting url will be constructed this way :
|
|
|
- *
|
|
|
- * Edition : ({baseUrl}/){apiResource.entity}/{id}
|
|
|
- * Creation : ({baseUrl}/){apiResource.entity}/new
|
|
|
- */
|
|
|
- baseRoute: {
|
|
|
- type: String,
|
|
|
- required: false,
|
|
|
- default: '/parameters'
|
|
|
+ items: {
|
|
|
+ type: Array as PropType<Array<object>>,
|
|
|
+ required: true,
|
|
|
},
|
|
|
/**
|
|
|
* If provided, define the columns to show.
|
|
|
@@ -117,6 +92,14 @@ const props = defineProps({
|
|
|
required: false,
|
|
|
default: null
|
|
|
},
|
|
|
+ /**
|
|
|
+ * The property used as identifier (required by 'edition' link)
|
|
|
+ */
|
|
|
+ identifier: {
|
|
|
+ type: String,
|
|
|
+ required: false,
|
|
|
+ default: 'id'
|
|
|
+ },
|
|
|
/**
|
|
|
* List of the actions available for each record
|
|
|
*/
|
|
|
@@ -126,101 +109,36 @@ const props = defineProps({
|
|
|
default: [TABLE_ACTION.EDIT, TABLE_ACTION.DELETE, TABLE_ACTION.ADD]
|
|
|
},
|
|
|
/**
|
|
|
- * If provided, sort the record by the given property
|
|
|
+ * The URL for the edit / create pages
|
|
|
+ * The resulting url will be constructed this way :
|
|
|
+ *
|
|
|
+ * Edition : {baseUrl}/{id}
|
|
|
+ * Creation : {baseUrl}/new
|
|
|
*/
|
|
|
- sortBy: {
|
|
|
- type: String as PropType<string>,
|
|
|
+ actionsRoute: {
|
|
|
+ type: String,
|
|
|
required: false,
|
|
|
- default: 'id'
|
|
|
+ default: '/parameters'
|
|
|
}
|
|
|
})
|
|
|
|
|
|
const i18n = useI18n()
|
|
|
|
|
|
-const { fetchCollection } = useEntityFetch()
|
|
|
+const emit = defineEmits(['editClicked', 'deleteClicked', 'addClicked'])
|
|
|
|
|
|
-const {
|
|
|
- data: collection,
|
|
|
- pending,
|
|
|
-} = fetchCollection(props.model)
|
|
|
+const getId = (item: object) => {
|
|
|
+ return item[props.identifier]
|
|
|
+}
|
|
|
|
|
|
-/**
|
|
|
- * Return the properties to display in the table, or all the
|
|
|
- * props of the model if not specified.
|
|
|
- */
|
|
|
const columns: ComputedRef<Array<ColumnDefinition>> = computed(() => {
|
|
|
- let columns: Array<ColumnDefinition>
|
|
|
-
|
|
|
- if (!props.columnsDefinitions) {
|
|
|
- const entityProps = Object.getOwnPropertyNames(new props.model())
|
|
|
-
|
|
|
- columns = entityProps.map(prop => {
|
|
|
- return {
|
|
|
- property: prop,
|
|
|
- label: i18n.t(prop)
|
|
|
- }
|
|
|
- })
|
|
|
- } else {
|
|
|
- columns = props.columnsDefinitions
|
|
|
-
|
|
|
- columns = columns.map(col => {
|
|
|
- return {
|
|
|
- property: col.property,
|
|
|
- label: col.label ?? i18n.t(col.property)
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- return columns
|
|
|
-})
|
|
|
-
|
|
|
-/**
|
|
|
- * Fetch the collection of ApiResources of the given model, then
|
|
|
- * map it according to the configuration.
|
|
|
- */
|
|
|
-const items: ComputedRef<Array<ApiResource> | null> = computed(() => {
|
|
|
- if (pending.value || collection.value === null) {
|
|
|
- return null
|
|
|
- }
|
|
|
-
|
|
|
- let items: Array<ApiResource> = collection.value!.items
|
|
|
-
|
|
|
- if (props.columnsDefinitions !== null) {
|
|
|
- // Filter the columns to show
|
|
|
- items = items.map(item => {
|
|
|
- const newItem: ApiResource = { id: item.id }
|
|
|
- for (const col of props.columnsDefinitions) {
|
|
|
- newItem[col.property] = item[col.property]
|
|
|
- }
|
|
|
- return newItem
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- if (props.sortBy) {
|
|
|
- items = items.sort((a: AssociativeArray, b: AssociativeArray) => {
|
|
|
- return (a[props.sortBy as keyof typeof a] > b[props.sortBy as keyof typeof b]) ? 1 : -1
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- return items
|
|
|
+ return props.columnsDefinitions.map(col => {
|
|
|
+ return {
|
|
|
+ property: col.property,
|
|
|
+ label: col.label ?? i18n.t(col.property)
|
|
|
+ }
|
|
|
+ })
|
|
|
})
|
|
|
|
|
|
-/**
|
|
|
- * Redirect to the edition page for the given item
|
|
|
- * @param id
|
|
|
- */
|
|
|
-const goToEditPage = (id: number) => {
|
|
|
- console.log(props.baseRoute, props.model.entity, id, UrlUtils.join(props.baseRoute, props.model.entity, id))
|
|
|
- navigateTo(UrlUtils.join(props.baseRoute, props.model.entity, id))
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * Redirect to the creation page for this model
|
|
|
- */
|
|
|
-const goToCreatePage = () => {
|
|
|
- navigateTo(UrlUtils.join(props.baseRoute, props.model.entity, 'new'))
|
|
|
-}
|
|
|
-
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|