EntityTable.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <!--
  2. A data table for the parameters page
  3. -->
  4. <template>
  5. <div class="container">
  6. <UiLoadingPanel v-if="status === FETCHING_STATUS.PENDING" />
  7. <div v-else>
  8. <LayoutParametersTable
  9. :items="items"
  10. :title="title"
  11. :columns-definitions="columns"
  12. :actions="actions"
  13. :actions-route="actionsRoute"
  14. @edit-clicked="onEditClicked"
  15. @delete-clicked="onDeleteClicked"
  16. @add-clicked="goToCreatePage"
  17. />
  18. <UiFormDeletionConfirmationDialog
  19. v-model="showDeletionConfirmationDialog"
  20. @delete-clicked="onDeleteConfirmed"
  21. @cancel-clicked="onCancelClicked"
  22. />
  23. </div>
  24. </div>
  25. </template>
  26. <script setup lang="ts">
  27. import { TABLE_ACTION } from '~/types/enum/enums'
  28. import UrlUtils from '~/services/utils/urlUtils'
  29. import type ApiResource from '~/models/ApiResource'
  30. import { useEntityFetch } from '~/composables/data/useEntityFetch'
  31. import type { AssociativeArray } from '~/types/data'
  32. import type { ColumnDefinition } from '~/types/interfaces'
  33. import { useDeleteItem } from '~/composables/form/useDeleteItem'
  34. import { useEntityManager } from '~/composables/data/useEntityManager'
  35. import { FETCHING_STATUS } from '~/types/enum/data'
  36. const props = defineProps({
  37. /**
  38. * The model whom entities shall be to fetch
  39. */
  40. model: {
  41. type: Object as PropType<typeof ApiResource>,
  42. required: true,
  43. },
  44. /** Titre du tableau */
  45. title: {
  46. type: String,
  47. required: false,
  48. default: null,
  49. },
  50. /**
  51. * If provided, define the columns to show.
  52. * Else, all the entity's props are shown.
  53. *
  54. * Ex: [
  55. * { property: 'id', label : 'Identifier'},
  56. * { property: 'name', label : 'Full name'},
  57. * ]
  58. */
  59. columnsDefinitions: {
  60. type: Array as PropType<Array<ColumnDefinition> | null>,
  61. required: false,
  62. default: null,
  63. },
  64. /**
  65. * List of the actions available for each record
  66. */
  67. actions: {
  68. type: Array as PropType<Array<TABLE_ACTION>>,
  69. required: false,
  70. default: () => [TABLE_ACTION.EDIT, TABLE_ACTION.DELETE, TABLE_ACTION.ADD],
  71. },
  72. /**
  73. * The base URL for the edit / create pages
  74. * The resulting url will be constructed this way :
  75. *
  76. * Edition : ({baseUrl}/){apiResource.entity}/{id}
  77. * Creation : ({baseUrl}/){apiResource.entity}/new
  78. */
  79. baseActionsRoute: {
  80. type: String,
  81. required: false,
  82. default: '/parameters',
  83. },
  84. /**
  85. * If provided, sort the record by the given property
  86. */
  87. sortBy: {
  88. type: String as PropType<string>,
  89. required: false,
  90. default: 'id',
  91. },
  92. })
  93. const i18n = useI18n()
  94. const { em } = useEntityManager()
  95. const { fetchCollection } = useEntityFetch()
  96. const { data: collection, status } = fetchCollection(props.model)
  97. const { deleteItem } = useDeleteItem()
  98. const pageStore = usePageStore()
  99. /**
  100. * Return the properties to display in the table, or all the
  101. * props of the model if not specified.
  102. */
  103. const columns: ComputedRef<Array<ColumnDefinition>> = computed(() => {
  104. return (
  105. props.columnsDefinitions ??
  106. Object.getOwnPropertyNames(new props.model()).map((prop) => {
  107. return { property: prop }
  108. })
  109. )
  110. })
  111. /**
  112. * Fetch the collection of ApiResources of the given model, then
  113. * map it according to the configuration.
  114. */
  115. const items: ComputedRef<Array<ApiResource> | null> = computed(() => {
  116. if (status.value === FETCHING_STATUS.PENDING || collection.value === null) {
  117. return null
  118. }
  119. let items: Array<ApiResource> = collection.value!.items
  120. if (props.columnsDefinitions !== null) {
  121. // Filter the columns to show
  122. items = items.map((item) => {
  123. const newItem: ApiResource = { id: item.id }
  124. for (const col of props.columnsDefinitions!) {
  125. newItem[col.property] = item[col.property]
  126. }
  127. return newItem
  128. })
  129. }
  130. if (props.sortBy) {
  131. items = items.sort((a: AssociativeArray, b: AssociativeArray) => {
  132. return a[props.sortBy as keyof typeof a] >
  133. b[props.sortBy as keyof typeof b]
  134. ? 1
  135. : -1
  136. })
  137. }
  138. return items
  139. })
  140. const actionsRoute = computed(() => {
  141. return UrlUtils.join(props.baseActionsRoute, props.model.entity)
  142. })
  143. const showDeletionConfirmationDialog: Ref<boolean> = ref(false)
  144. const itemToDelete: Ref<ApiResource | null> = ref(null)
  145. /**
  146. * Redirect to the edition page for the given item
  147. * @param item
  148. */
  149. const onEditClicked = (item: ApiResource) => {
  150. navigateTo(UrlUtils.join(actionsRoute.value, item.id))
  151. }
  152. /**
  153. * Show the deletion confirmation dialog
  154. * @param item
  155. */
  156. const onDeleteClicked = (item: ApiResource) => {
  157. itemToDelete.value = em.cast(props.model, item)
  158. showDeletionConfirmationDialog.value = true
  159. }
  160. const onCancelClicked = () => {
  161. itemToDelete.value = null
  162. }
  163. /**
  164. * Deletion has be confirmed, perform
  165. */
  166. const onDeleteConfirmed = async () => {
  167. pageStore.loading = true
  168. await deleteItem(itemToDelete.value)
  169. pageStore.loading = false
  170. }
  171. /**
  172. * Redirect to the creation page for this model
  173. */
  174. const goToCreatePage = () => {
  175. navigateTo(UrlUtils.join(actionsRoute.value, 'new'))
  176. }
  177. // Nettoyer les données lors du démontage du composant
  178. onBeforeUnmount(() => {
  179. // Nettoyer les références du store si nécessaire
  180. if (import.meta.client) {
  181. clearNuxtData('/^' + props.model.entity + '_many_/')
  182. useRepo(props.model).flush()
  183. }
  184. })
  185. </script>
  186. <style scoped lang="scss"></style>