Explorar o código

finalize the ParametersTable component

Olivier Massot hai 10 meses
pai
achega
4733699a35
Modificáronse 2 ficheiros con 74 adicións e 59 borrados
  1. 73 57
      components/Layout/Parameters/Table.vue
  2. 1 2
      pages/parameters/attendances.vue

+ 73 - 57
components/Layout/Parameters/Table.vue

@@ -1,25 +1,28 @@
+<!--
+A data table for the parameters page
+-->
 <template>
   <div>
     <UiLoadingPanel v-if="pending" />
     <v-table v-else>
       <thead>
         <tr>
-          <td v-for="(_, i) in actualColumnProps">
-            {{ actualColumnLabels[i] ?? '' }}
+          <td v-for="col in columns">
+            {{ col.label }}
           </td>
           <td>{{ $t('actions') }}</td>
         </tr>
       </thead>
-      <tbody v-if="items.value">
+      <tbody v-if="items">
         <tr
-          v-for="item in items.value"
-          :key="item.id"
+          v-for="(item, i) in items"
+          :key="i"
         >
           <td
-            v-for="prop in actualColumnProps"
+            v-for="col in columns"
             class="cycle-editable-cell"
           >
-            {{ item[prop] }}
+            {{ item[col.property] }}
           </td>
 
           <td class="d-flex flex-row">
@@ -60,11 +63,25 @@
 </template>
 
 <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 | null
+}
 
 const props = defineProps({
   /**
@@ -78,35 +95,27 @@ const props = defineProps({
    * 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
+   * Edition : ({baseUrl}/){apiResource.entity}/{id}
+   * Creation : ({baseUrl}/){apiResource.entity}/new
    */
   baseRoute: {
     type: String,
     required: false,
-    default: 'parameters'
-  },
-  /**
-   * If provided, limit the properties shown in the table to this list.
-   * Else, all the props are shown.
-   *
-   * Ex: ['id', 'name']
-   */
-  columnsProps: {
-    type: Array as PropType<Array<string>>,
-    required: false
+    default: ''
   },
   /**
-   * If provided, add labels to the columns
-   *
-   * Ex: ['Identifier', 'Full Name']
+   * If provided, define the columns to show.
+   * Else, all the entity's props are shown.
    *
-   * If not provided, a translation of the entity's props names will be looked for.
-   * If none is found, no title will be displayed.
+   * Ex: [
+   *       { property: 'id', label : 'Identifier'},
+   *       { property: 'name', label : 'Full name'},
+   *     ]
    */
-  columnsLabels: {
-    type: Array as PropType<Array<string>>,
-    required: false
+  columnsDefinitions: {
+    type: Array as PropType<Array<ColumnDefinition> | null>,
+    required: false,
+    default: null
   },
   /**
    * List of the actions available for each record
@@ -120,7 +129,7 @@ const props = defineProps({
    * If provided, sort the record by the given property
    */
   sortBy: {
-    type: String,
+    type: String as PropType<string>,
     required: false,
     default: 'id'
   }
@@ -139,50 +148,57 @@ const {
  * Return the properties to display in the table, or all the
  * props of the model if not specified.
  */
-const actualColumnProps = computed(() => {
-  if (props.columnsProps) {
-    return props.columnsProps
-  }
-  return Object.getOwnPropertyNames(new props.model())
-})
+const columns: ComputedRef<Array<ColumnDefinition>> = computed(() => {
+  let columns: Array<ColumnDefinition>
 
-/**
- * Return the labels for the columns if provided, or try to
- * find a translation for the property name if not specified.
- */
-const actualColumnLabels: ComputedRef<string> = computed(() => {
-  if (props.columnsLabels) {
-    return props.columnsLabels
+  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 actualColumnProps.value.map(prop => {
-    return i18n.t(prop) ?? ''
-  })
+
+  return columns
 })
 
 /**
  * Fetch the collection of ApiResources of the given model, then
  * map it according to the configuration.
  */
-const items: ComputedRef<Array<object>> = computed(() => {
-  if (pending.value) {
+const items: ComputedRef<Array<ApiResource> | null> = computed(() => {
+  if (pending.value || collection.value === null) {
     return null
   }
 
-  const items: Ref<object[]> = ref(collection.value.items)
+  let items: Array<ApiResource> = collection.value!.items
 
-  if (props.columnsProps) {
-    items.value = items.value.map(item => {
-      const res = {}
-      for (const prop of props.columnsProps) {
-        res[prop] = item[prop]
+  if (props.columnsDefinitions !== null) {
+    // Filter the columns to show
+    items = items.map(item => {
+      const newItem: ApiResource = {}
+      for (const col of props.columnsDefinitions) {
+        newItem[col.property] = item[col.property]
       }
-      return res
+      return newItem
     })
   }
 
   if (props.sortBy) {
-    items.value = items.value.sort((a, b) => {
-      return a[props.sortBy] > b[props.sortBy] ? 1 : -1
+    items = items.sort((a: AssociativeArray, b: AssociativeArray) => {
+      return (a[props.sortBy as keyof typeof a] > b[props.sortBy as keyof typeof b]) ? 1 : -1
     })
   }
 

+ 1 - 2
pages/parameters/attendances.vue

@@ -40,7 +40,7 @@
 
     <LayoutParametersTable
       :model="AttendanceBookingReason"
-      :columns-props="['reason']"
+      :columns-definitions="[{ property: 'reason' }]"
     />
   </LayoutContainer>
 </template>
@@ -71,7 +71,6 @@ const { data: parameters, pending } = fetch(
   organizationProfile.parametersId,
 ) as AsyncData<Parameters | null, Error | null>
 
-
 const rules = () => [
   (numberConsecutiveAbsences: string | null) =>
     (numberConsecutiveAbsences !== null &&