Table.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <!--
  2. A data table for the parameters page
  3. -->
  4. <template>
  5. <div class="container">
  6. <v-table>
  7. <thead>
  8. <tr>
  9. <td v-for="col in columns">
  10. {{ col.label }}
  11. </td>
  12. <td>{{ i18n.t('actions') }}</td>
  13. </tr>
  14. </thead>
  15. <tbody v-if="items">
  16. <tr
  17. v-for="(item, i) in items"
  18. :key="i"
  19. >
  20. <td
  21. v-for="col in columnsDefinitions"
  22. class="cycle-editable-cell"
  23. >
  24. {{ item[col.property] }}
  25. </td>
  26. <td class="d-flex flex-row actions-cell">
  27. <slot name="actions" :item="item">
  28. <v-btn
  29. v-if="actions.includes(TABLE_ACTION.EDIT)"
  30. :flat="true"
  31. icon="fa fa-pen"
  32. class="mr-3"
  33. @click="emit('editClicked', item)"
  34. />
  35. <v-btn
  36. v-if="actions.includes(TABLE_ACTION.DELETE)"
  37. :flat="true"
  38. icon="fas fa-trash"
  39. @click="emit('deleteClicked', item)"
  40. />
  41. </slot>
  42. </td>
  43. </tr>
  44. </tbody>
  45. <tbody v-else>
  46. <tr class="theme-neutral">
  47. <td>
  48. <i>{{ i18n.t('nothing_to_show') }}</i>
  49. </td>
  50. <td></td>
  51. </tr>
  52. </tbody>
  53. </v-table>
  54. <div class="d-flex justify-end" v-if="actions.includes(TABLE_ACTION.ADD)">
  55. <v-btn
  56. :flat="true"
  57. prepend-icon="fa fa-plus"
  58. class="theme-primary mt-4"
  59. @click="emit('addClicked')"
  60. >
  61. {{ i18n.t('add') }}
  62. </v-btn>
  63. </div>
  64. </div>
  65. </template>
  66. <script setup lang="ts">
  67. import {TABLE_ACTION} from '~/types/enum/enums';
  68. import UrlUtils from '~/services/utils/urlUtils';
  69. import type {ColumnDefinition} from '~/types/interfaces';
  70. const props = defineProps({
  71. /**
  72. * Array of objects to display in the table
  73. */
  74. items: {
  75. type: Array as PropType<Array<object>>,
  76. required: true,
  77. },
  78. /**
  79. * If provided, define the columns to show.
  80. * Else, all the entity's props are shown.
  81. *
  82. * Ex: [
  83. * { property: 'id', label : 'Identifier'},
  84. * { property: 'name', label : 'Full name'},
  85. * ]
  86. */
  87. columnsDefinitions: {
  88. type: Array as PropType<Array<ColumnDefinition> | null>,
  89. required: false,
  90. default: null
  91. },
  92. /**
  93. * The property used as identifier (required by 'edition' link)
  94. */
  95. identifier: {
  96. type: String,
  97. required: false,
  98. default: 'id'
  99. },
  100. /**
  101. * List of the actions available for each record
  102. */
  103. actions: {
  104. type: Array as PropType<Array<TABLE_ACTION>>,
  105. required: false,
  106. default: [TABLE_ACTION.EDIT, TABLE_ACTION.DELETE, TABLE_ACTION.ADD]
  107. },
  108. /**
  109. * The URL for the edit / create pages
  110. * The resulting url will be constructed this way :
  111. *
  112. * Edition : {baseUrl}/{id}
  113. * Creation : {baseUrl}/new
  114. */
  115. actionsRoute: {
  116. type: String,
  117. required: false,
  118. default: '/parameters'
  119. }
  120. })
  121. const i18n = useI18n()
  122. const emit = defineEmits(['editClicked', 'deleteClicked', 'addClicked'])
  123. const getId = (item: object) => {
  124. return item[props.identifier]
  125. }
  126. const columns: ComputedRef<Array<ColumnDefinition>> = computed(() => {
  127. return props.columnsDefinitions.map(col => {
  128. return {
  129. property: col.property,
  130. label: col.label ?? i18n.t(col.property)
  131. }
  132. })
  133. })
  134. </script>
  135. <style scoped lang="scss">
  136. .container {
  137. max-width: 1000px;
  138. }
  139. .v-table {
  140. width: 100%;
  141. thead {
  142. color: rgb(var(--v-theme-neutral-strong));
  143. font-weight: 600;
  144. td {
  145. border-bottom: thin solid rgba(var(--v-border-color), var(--v-border-opacity));
  146. }
  147. td:last-of-type {
  148. padding-left: 30px;
  149. }
  150. }
  151. th, td {
  152. padding: 10px;
  153. text-align: left;
  154. }
  155. td:last-of-type {
  156. width: 125px;
  157. }
  158. }
  159. :deep(.actions-cell .v-icon) {
  160. color: rgb(var(--v-theme-neutral-strong));
  161. font-size: 18px;
  162. }
  163. </style>