@cnamts/synapse 1.0.1 → 1.0.2

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.
Files changed (217) hide show
  1. package/README.md +1 -1
  2. package/dist/{DateFilter-BmRuzQ9Z.js → DateFilter-YWOTbfeL.js} +1 -1
  3. package/dist/{NumberFilter-CnIPDHqx.js → NumberFilter-DMmMgALM.js} +1 -1
  4. package/dist/{PeriodFilter-CZwZ8CnQ.js → PeriodFilter-Bok5BHcn.js} +1 -1
  5. package/dist/SelectFilter-BKud2WhN.js +136 -0
  6. package/dist/{TextFilter-DTxZHJwX.js → TextFilter-DvMf2thH.js} +1 -1
  7. package/dist/components/Accordion/Accordion.d.ts +2 -1
  8. package/dist/components/Accordion/composables/useAccordionGroupCommunication.d.ts +5 -0
  9. package/dist/components/Accordion/composables/useAccordionKeyboardNavigation.d.ts +12 -0
  10. package/dist/components/Accordion/composables/useAccordionState.d.ts +13 -0
  11. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +85 -0
  12. package/dist/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -0
  13. package/dist/components/Customs/SySelect/SySelect.d.ts +33 -13
  14. package/dist/components/Customs/SyTextField/SyTextField.d.ts +2 -2
  15. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +1585 -1452
  16. package/dist/components/DatePicker/DatePicker/DatePicker.d.ts +16 -2
  17. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +3 -1
  18. package/dist/components/DatePicker/composables/index.d.ts +2 -0
  19. package/dist/components/DatePicker/composables/useAsteriskDisplay.d.ts +14 -0
  20. package/dist/components/DatePicker/composables/useDateAutoClamp.d.ts +16 -0
  21. package/dist/components/DatePicker/composables/useDateRangeInput.d.ts +1 -1
  22. package/dist/components/DatePicker/composables/useDisplayedDateString.d.ts +3 -0
  23. package/dist/components/DatePicker/composables/useInputBlurHandler.d.ts +1 -0
  24. package/dist/components/DatePicker/composables/useMonthButtonCustomization.d.ts +5 -2
  25. package/dist/components/NirField/NirField.d.ts +7 -3
  26. package/dist/components/NirField/nirValidation.d.ts +1 -1
  27. package/dist/components/PasswordField/PasswordField.d.ts +2 -0
  28. package/dist/components/PeriodField/PeriodField.d.ts +52 -8
  29. package/dist/components/PhoneField/PhoneField.d.ts +2 -2
  30. package/dist/components/RangeField/RangeField.d.ts +2 -0
  31. package/dist/components/SearchListField/SearchListField.d.ts +9 -0
  32. package/dist/components/SyTextArea/SyTextArea.d.ts +2 -0
  33. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +14 -9
  34. package/dist/components/Tables/SyTable/SyTable.d.ts +12 -7
  35. package/dist/components/Tables/common/SyTablePagination.d.ts +1636 -0
  36. package/dist/components/Tables/common/TableHeader.d.ts +2 -20
  37. package/dist/components/Tables/common/filters/SelectFilter.d.ts +5 -5
  38. package/dist/components/Tables/common/filters/getFilterComponent.d.ts +1 -0
  39. package/dist/components/Tables/common/filters/locales.d.ts +4 -0
  40. package/dist/components/Tables/common/filters/logics/date.d.ts +1 -0
  41. package/dist/components/Tables/common/filters/logics/number.d.ts +1 -0
  42. package/dist/components/Tables/common/filters/logics/period.d.ts +1 -0
  43. package/dist/components/Tables/common/filters/logics/select.d.ts +1 -0
  44. package/dist/components/Tables/common/filters/logics/text.d.ts +1 -0
  45. package/dist/components/Tables/common/locales.d.ts +21 -0
  46. package/dist/components/Tables/common/organizeColumns/OrganizeColumns.d.ts +267 -0
  47. package/dist/components/Tables/common/organizeColumns/sortHeaders.d.ts +2 -0
  48. package/dist/components/Tables/common/tableFilterUtils.d.ts +1 -0
  49. package/dist/components/Tables/common/tableStorageUtils.d.ts +41 -1
  50. package/dist/components/Tables/common/tableUtils.d.ts +42 -5
  51. package/dist/components/Tables/common/types.d.ts +19 -8
  52. package/dist/components/Tables/common/usePagination.d.ts +22 -0
  53. package/dist/components/Tables/common/useTableCheckbox.d.ts +20 -0
  54. package/dist/components/Tables/common/useTableHeaders.d.ts +76 -0
  55. package/dist/components/Tables/common/useTableItems.d.ts +24 -0
  56. package/dist/components/Tables/common/useTableOptions.d.ts +18 -0
  57. package/dist/components/ToolbarContainer/ToolbarContainer.d.ts +11 -0
  58. package/dist/components/UserMenuBtn/UserMenuBtn.d.ts +9 -2
  59. package/dist/components/index.d.ts +8 -6
  60. package/dist/design-system-v3.js +58 -56
  61. package/dist/design-system-v3.umd.cjs +22 -22
  62. package/dist/main-Cx8qG7YR.js +16344 -0
  63. package/dist/stories/Accessibilite/Vuetify/VuetifyItems.d.ts +14 -2
  64. package/dist/stories/DesignTokens/StylesTypographiques.stories.new.d.ts +8 -0
  65. package/dist/stories/DesignTokens/TypographyDisplay.d.ts +28 -0
  66. package/dist/stories/DesignTokens/vue-shims.d.ts +6 -0
  67. package/dist/style.css +1 -1
  68. package/package.json +1 -1
  69. package/src/common/imgs/accessibility-svgrepo-com.svg +4 -0
  70. package/src/components/Accordion/Accessibilite/AccessibilityGuide.mdx +249 -0
  71. package/src/components/Accordion/Accordion.vue +48 -76
  72. package/src/components/Accordion/composables/__tests__/useAccordionGroupCommunication.spec.ts +146 -0
  73. package/src/components/Accordion/composables/__tests__/useAccordionKeyboardNavigation.spec.ts +209 -0
  74. package/src/components/Accordion/composables/__tests__/useAccordionState.spec.ts +144 -0
  75. package/src/components/Accordion/composables/useAccordionGroupCommunication.ts +52 -0
  76. package/src/components/Accordion/composables/useAccordionKeyboardNavigation.ts +111 -0
  77. package/src/components/Accordion/composables/useAccordionState.ts +59 -0
  78. package/src/components/Accordion/tests/__snapshots__/accordion.spec.ts.snap +3 -0
  79. package/src/components/Customs/SyCheckbox/Accessibilite.mdx +303 -0
  80. package/src/components/Customs/SyCheckbox/SyCheckbox.mdx +50 -0
  81. package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +630 -0
  82. package/src/components/Customs/SyCheckbox/SyCheckbox.vue +326 -0
  83. package/src/components/Customs/SyCheckbox/tests/SyCheckbox.spec.ts +201 -0
  84. package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +1 -0
  85. package/src/components/Customs/SyInputSelect/SyInputSelect.vue +8 -1
  86. package/src/components/Customs/SySelect/SySelect.stories.ts +160 -0
  87. package/src/components/Customs/SySelect/SySelect.vue +291 -32
  88. package/src/components/Customs/SySelect/tests/SySelect.spec.ts +230 -0
  89. package/src/components/Customs/SyTextField/SyTextField.stories.ts +3 -2
  90. package/src/components/Customs/SyTextField/SyTextField.vue +19 -8
  91. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +241 -31
  92. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +305 -57
  93. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.events.spec.ts +161 -0
  94. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +4 -2
  95. package/src/components/DatePicker/DatePicker/DatePicker.stories.ts +259 -137
  96. package/src/components/DatePicker/DatePicker/DatePicker.vue +153 -25
  97. package/src/components/DatePicker/DatePicker/tests/DatePicker.events.spec.ts +189 -0
  98. package/src/components/DatePicker/DatePicker/{DatePicker.spec.ts → tests/DatePicker.spec.ts} +1 -15
  99. package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +24 -14
  100. package/src/components/DatePicker/DateTextInput/DateTextInput.events.spec.ts +148 -0
  101. package/src/components/DatePicker/DateTextInput/DateTextInput.spec.ts +3 -1
  102. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +200 -5
  103. package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +241 -31
  104. package/src/components/DatePicker/composables/index.ts +2 -0
  105. package/src/components/DatePicker/composables/tests/useDateAutoClamp.spec.ts +190 -0
  106. package/src/components/DatePicker/composables/tests/useInputBlurHandler.spec.ts +182 -4
  107. package/src/components/DatePicker/composables/tests/useMonthButtonCustomization.spec.ts +105 -80
  108. package/src/components/DatePicker/composables/useAsteriskDisplay.ts +31 -0
  109. package/src/components/DatePicker/composables/useDateAutoClamp.ts +136 -0
  110. package/src/components/DatePicker/composables/useDateRangeInput.ts +21 -18
  111. package/src/components/DatePicker/composables/useDisplayedDateString.ts +13 -1
  112. package/src/components/DatePicker/composables/useInputBlurHandler.ts +84 -20
  113. package/src/components/DatePicker/composables/useMonthButtonCustomization.ts +149 -51
  114. package/src/components/DiacriticPicker/DiacriticPicker.stories.ts +10 -0
  115. package/src/components/ErrorPage/Accessibilite.stories.ts +8 -0
  116. package/src/components/ErrorPage/ErrorPage.vue +12 -6
  117. package/src/components/ErrorPage/tests/__snapshots__/ErrorPage.spec.ts.snap +4 -4
  118. package/src/components/NirField/NirField.mdx +22 -9
  119. package/src/components/NirField/NirField.stories.ts +26 -2
  120. package/src/components/NirField/NirField.vue +209 -22
  121. package/src/components/NirField/nirValidation.ts +17 -3
  122. package/src/components/NirField/tests/NirField.spec.ts +2 -2
  123. package/src/components/NotFoundPage/Accessibilite.stories.ts +8 -0
  124. package/src/components/NotFoundPage/NotFoundPage.vue +2 -1
  125. package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +8 -6
  126. package/src/components/PaginatedTable/PaginatedTable.mdx +2 -0
  127. package/src/components/PasswordField/PasswordField.stories.ts +4 -0
  128. package/src/components/PasswordField/PasswordField.vue +3 -0
  129. package/src/components/PeriodField/PeriodField.vue +2 -0
  130. package/src/components/PhoneField/PhoneField.stories.ts +15 -15
  131. package/src/components/PhoneField/PhoneField.vue +1 -1
  132. package/src/components/RangeField/RangeField.stories.ts +9 -0
  133. package/src/components/RangeField/RangeField.vue +4 -0
  134. package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +12 -0
  135. package/src/components/SearchListField/SearchListField.vue +5 -0
  136. package/src/components/SyTextArea/SyTextArea.vue +3 -0
  137. package/src/components/SyTextArea/tests/SyTextArea.spec.ts +0 -1
  138. package/src/components/Tables/SyServerTable/FilterRules.stories.ts +632 -15
  139. package/src/components/Tables/SyServerTable/SyServerTable.mdx +15 -5
  140. package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +2844 -1377
  141. package/src/components/Tables/SyServerTable/SyServerTable.vue +155 -66
  142. package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +256 -4
  143. package/src/components/Tables/SyTable/FilterRules.stories.ts +183 -0
  144. package/src/components/Tables/SyTable/SyTable.mdx +14 -4
  145. package/src/components/Tables/SyTable/SyTable.stories.ts +1265 -477
  146. package/src/components/Tables/SyTable/SyTable.vue +152 -72
  147. package/src/components/Tables/SyTable/tests/SyTable.spec.ts +366 -4
  148. package/src/components/Tables/common/SyTableFilter.vue +3 -56
  149. package/src/components/Tables/common/SyTablePagination.vue +375 -0
  150. package/src/components/Tables/common/TableHeader.vue +10 -26
  151. package/src/components/Tables/common/filters/SelectFilter.vue +131 -22
  152. package/src/components/Tables/common/filters/getFilterComponent.ts +54 -0
  153. package/src/components/Tables/common/filters/locales.ts +4 -0
  154. package/src/components/Tables/common/filters/logics/date.ts +12 -0
  155. package/src/components/Tables/common/filters/logics/number.ts +48 -0
  156. package/src/components/Tables/common/filters/logics/period.ts +25 -0
  157. package/src/components/Tables/common/filters/logics/select.ts +27 -0
  158. package/src/components/Tables/common/filters/logics/tests/TextFilterLogic.spec.ts +177 -0
  159. package/src/components/Tables/common/filters/logics/text.ts +62 -0
  160. package/src/components/Tables/common/filters/tests/TextFilter.spec.ts +11 -11
  161. package/src/components/Tables/common/locales.ts +24 -0
  162. package/src/components/Tables/common/organizeColumns/OrganizeColumns.vue +269 -0
  163. package/src/components/Tables/common/organizeColumns/sortHeaders.ts +9 -0
  164. package/src/components/Tables/common/tableFilterUtils.ts +43 -295
  165. package/src/components/Tables/common/tableStorageUtils.ts +27 -2
  166. package/src/components/Tables/common/tableStyles.scss +26 -0
  167. package/src/components/Tables/common/tableUtils.ts +3 -16
  168. package/src/components/Tables/common/tests/SyTablePagination.spec.ts +170 -0
  169. package/src/components/Tables/common/tests/filterByRange.spec.ts +215 -0
  170. package/src/components/Tables/common/tests/tableFilterUtils.spec.ts +0 -14
  171. package/src/components/Tables/common/tests/tableUtils.spec.ts +7 -51
  172. package/src/components/Tables/common/types.ts +17 -6
  173. package/src/components/Tables/common/usePagination.ts +83 -0
  174. package/src/components/Tables/common/useTableCheckbox.ts +58 -0
  175. package/src/components/Tables/common/useTableHeaders.ts +88 -0
  176. package/src/components/Tables/common/useTableItems.ts +87 -0
  177. package/src/components/Tables/common/useTableOptions.ts +93 -0
  178. package/src/components/ToolbarContainer/ToolbarContainer.mdx +16 -0
  179. package/src/components/ToolbarContainer/ToolbarContainer.stories.ts +675 -0
  180. package/src/components/ToolbarContainer/ToolbarContainer.vue +128 -0
  181. package/src/components/ToolbarContainer/tests/ToolbarContainer.spec.ts +156 -0
  182. package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +74 -0
  183. package/src/components/UserMenuBtn/UserMenuBtn.vue +19 -17
  184. package/src/components/index.ts +8 -6
  185. package/src/stories/Accessibilite/Aculturation/AuditDesignSystem.mdx +293 -20
  186. package/src/stories/Accessibilite/Aculturation/SensibilisationAccessibilite.mdx +448 -54
  187. package/src/stories/Accessibilite/Audit/RGAA.mdx +231 -23
  188. package/src/stories/Accessibilite/Avancement/Avancement.mdx +591 -7
  189. package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +139 -38
  190. package/src/stories/Accessibilite/Introduction.mdx +258 -18
  191. package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +221 -31
  192. package/src/stories/Accessibilite/KitDePreAudit/Introduction.mdx +204 -22
  193. package/src/stories/Accessibilite/KitDePreAudit/Outils/Introduction.mdx +537 -24
  194. package/src/stories/Accessibilite/KitDePreAudit/Outils/LecteursDEcran.mdx +577 -70
  195. package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru.mdx +382 -31
  196. package/src/stories/Accessibilite/KitDePreAudit/Preaudit.mdx +419 -81
  197. package/src/stories/Accessibilite/Vuetify/Vuetify.mdx +132 -6
  198. package/src/stories/Accessibilite/Vuetify/Vuetify.stories.ts +370 -146
  199. package/src/stories/Accessibilite/Vuetify/VuetifyItems.ts +35 -57
  200. package/src/stories/Demarrer/Accueil.stories.ts +20 -5
  201. package/src/stories/DesignTokens/StylesTypographiques.mdx +10 -9
  202. package/src/stories/DesignTokens/StylesTypographiques.stories.new.ts +397 -0
  203. package/src/stories/DesignTokens/StylesTypographiques.stories.ts +397 -0
  204. package/src/stories/DesignTokens/TypographyDisplay.vue +155 -0
  205. package/src/stories/DesignTokens/vue-shims.d.ts +6 -0
  206. package/src/stories/GuideDuDev/LesBreackingChanges.mdx +0 -2
  207. package/src/stories/GuideDuDev/MigrationDepuisBridge.mdx +1 -1
  208. package/src/stories/GuideDuDev/MigrationDepuisVue2.mdx +1 -1
  209. package/src/stories/GuideDuDev/PortailAgent.mdx +10 -0
  210. package/src/stories/GuideDuDev/PortailAgent.stories.ts +506 -0
  211. package/src/stories/GuideDuDev/Theme.mdx +41 -0
  212. package/dist/SelectFilter-Cj-GW2Cc.js +0 -97
  213. package/dist/main-WDqeoGM-.js +0 -14788
  214. package/src/components/PaginatedTable/tests/__snapshots__/PaginatedTable.spec.ts.snap +0 -886
  215. package/src/components/Tables/SyServerTable/tests/__snapshots__/SyServerTable.spec.ts.snap +0 -521
  216. package/src/components/Tables/SyTable/tests/__snapshots__/SyTable.spec.ts.snap +0 -521
  217. package/src/stories/DesignTokens/ThemePA.mdx +0 -35
@@ -2,9 +2,10 @@ import type { Meta, StoryObj } from '@storybook/vue3'
2
2
  import SyServerTable from './SyServerTable.vue'
3
3
  import { StateEnum } from '../common/constants/StateEnum'
4
4
  import type { DataOptions, FilterType } from '../common/types'
5
- import { ref } from 'vue'
5
+ import { ref, watch } from 'vue'
6
6
  import type { VDataTable } from 'vuetify/components'
7
7
  import dayjs from 'dayjs'
8
+ import { fn } from '@storybook/test'
8
9
 
9
10
  interface User {
10
11
  [key: string]: string
@@ -31,7 +32,7 @@ const meta = {
31
32
  },
32
33
  argTypes: {
33
34
  headers: {
34
- description: 'Liste des colonnes du tableau',
35
+ description: 'Liste des colonnes du tableau (voir : https://vuetifyjs.com/en/api/v-data-table/#props-headers)',
35
36
  control: { type: 'object' },
36
37
  table: {
37
38
  category: 'props',
@@ -42,6 +43,9 @@ const meta = {
42
43
  control: { type: 'object' },
43
44
  table: {
44
45
  category: 'props',
46
+ defaultValue: {
47
+ summary: '[]',
48
+ },
45
49
  },
46
50
  },
47
51
  density: {
@@ -83,10 +87,6 @@ const meta = {
83
87
  },
84
88
  required: true,
85
89
  },
86
- itemsPerPage: {
87
- description: 'Nombre d\'éléments par page',
88
- control: { type: 'number' },
89
- },
90
90
  caption: {
91
91
  description: 'Texte de la légende du tableau',
92
92
  control: { type: 'text' },
@@ -94,6 +94,25 @@ const meta = {
94
94
  resizableColumns: {
95
95
  description: 'Permet de redimensionner les colonnes du tableau',
96
96
  },
97
+ enableColumnControls: {
98
+ description: 'Allow the users to re-organize the columns',
99
+ table: {
100
+ defaultValue: {
101
+ summary: 'false',
102
+ },
103
+ type: { summary: 'boolean' },
104
+ category: 'props',
105
+ },
106
+ control: { type: 'boolean' },
107
+ },
108
+ showSelect: {
109
+ description: 'Affiche des cases à cocher pour sélectionner des lignes',
110
+ control: { type: 'boolean' },
111
+ table: {
112
+ category: 'props',
113
+ type: { summary: 'boolean' },
114
+ },
115
+ },
97
116
  },
98
117
  } satisfies Meta<typeof SyServerTable & typeof VDataTable>
99
118
 
@@ -167,7 +186,7 @@ export const Default: Story = {
167
186
  return new Promise(resolve => setTimeout(resolve, ms))
168
187
  }
169
188
 
170
- const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise<DataObj> => {
189
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
171
190
  state.value = StateEnum.PENDING
172
191
  await wait(1000)
173
192
 
@@ -212,27 +231,31 @@ export const Default: Story = {
212
231
  { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' },
213
232
  ]
214
233
  }
234
+
235
+ // Initialize data
236
+ fetchData()
215
237
  </script>
216
238
  `,
217
239
  },
218
240
  ],
219
241
  },
220
242
  args: {
221
- options: {
243
+ 'options': {
222
244
  itemsPerPage: 5,
223
245
  sortBy: [{ key: 'lastname', order: 'asc' }],
224
246
  page: 1,
225
247
  },
226
- headers: [
248
+ 'headers': [
227
249
  { title: 'Nom', key: 'lastname' },
228
250
  { title: 'Prénom', key: 'firstname' },
229
251
  { title: 'Email', key: 'email' },
230
252
  ],
231
- caption: '',
232
- serverItemsLength: 15,
233
- suffix: 'server-default',
234
- density: 'default',
235
- striped: false,
253
+ 'caption': '',
254
+ 'serverItemsLength': 15,
255
+ 'suffix': 'server-default',
256
+ 'density': 'default',
257
+ 'striped': false,
258
+ 'onUpdate:options': fn(),
236
259
  },
237
260
  render: (args) => {
238
261
  return {
@@ -242,9 +265,16 @@ export const Default: Story = {
242
265
  const users = ref<User[]>([])
243
266
  const state = ref(StateEnum.IDLE)
244
267
 
268
+ const options = ref({ ...args.options })
269
+
270
+ watch(options, (newVal) => {
271
+ if (args.options) {
272
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
273
+ }
274
+ }, { deep: true })
275
+
245
276
  const fetchData = async (): Promise<void> => {
246
- // @ts-expect-error - fetchData is not defined
247
- const { items, total } = await getDataFromApi(args.options)
277
+ const { items, total } = await getDataFromApi(options.value as DataOptions)
248
278
  users.value = items
249
279
  totalUsers.value = total
250
280
  }
@@ -299,21 +329,19 @@ export const Default: Story = {
299
329
  ]
300
330
  }
301
331
 
302
- return { args, users, state, fetchData, totalUsers, StateEnum }
332
+ // Initialize data
333
+ fetchData()
334
+
335
+ return { args, users, state, fetchData, options, totalUsers, StateEnum }
303
336
  },
304
337
  template: `
305
338
  <div>
306
339
  <SyServerTable
307
- v-model:options="args.options"
340
+ v-model:options="options"
308
341
  :items="users"
309
- :headers="args.headers"
310
- :caption="args.caption"
311
342
  :server-items-length="totalUsers"
312
343
  :loading="state === StateEnum.PENDING"
313
- :suffix="args.suffix"
314
- :density="args.density"
315
- :striped="args.striped"
316
- :resizable-columns="args.resizableColumns"
344
+ v-bind="args"
317
345
  @update:options="fetchData"
318
346
  />
319
347
  </div>
@@ -328,127 +356,136 @@ export const ServerSortBy: Story = {
328
356
  {
329
357
  name: 'Template',
330
358
  code: `
331
- <template>
332
- <SyServerTable
333
- v-model:options="options"
334
- :items="users"
335
- :headers="headers"
336
- :server-items-length="totalUsers"
337
- :loading="state === StateEnum.PENDING"
338
- suffix="server-sort"
339
- @update:options="fetchData"
340
- />
341
- </template>
342
- `,
359
+ <template>
360
+ <SyServerTable
361
+ v-model:options="options"
362
+ :items="users"
363
+ :headers="headers"
364
+ :server-items-length="totalUsers"
365
+ :loading="state === StateEnum.PENDING"
366
+ suffix="server-sort"
367
+ @update:options="fetchData"
368
+ />
369
+ </template>
370
+ `,
343
371
  },
344
372
  {
345
373
  name: 'Script',
346
374
  code: `
347
- <script setup lang="ts">
348
- import { ref } from 'vue'
349
- import { SyServerTable } from '@cnamts/synapse'
350
- import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
351
- import type { DataOptions } from '@cnamts/synapse/src/components/Tables/common/types'
352
-
353
- interface User {
354
- [key: string]: string
355
- firstname: string
356
- lastname: string
357
- email: string
358
- }
359
-
360
- interface DataObj {
361
- items: User[]
362
- total: number
363
- }
364
-
365
- const totalUsers = ref(0)
366
- const users = ref<User[]>([])
367
- const state = ref(StateEnum.IDLE)
368
-
369
- const options = ref<DataOptions>({
370
- itemsPerPage: 5,
371
- sortBy: [{ key: 'lastname', order: 'desc' }],
372
- page: 1,
373
- })
374
-
375
- const headers = [
376
- { title: 'Nom', key: 'lastname' },
377
- { title: 'Prénom', key: 'firstname' },
378
- { title: 'Email', key: 'email' },
379
- ]
380
-
381
- const fetchData = async (): Promise<void> => {
382
- const { items, total } = await getDataFromApi(options.value)
383
- users.value = items
384
- totalUsers.value = total
385
- }
386
-
387
- const wait = async (ms: number) => {
388
- return new Promise(resolve => setTimeout(resolve, ms))
389
- }
390
-
391
- const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise<DataObj> => {
392
- state.value = StateEnum.PENDING
393
- await wait(1000)
394
-
395
- return new Promise((resolve) => {
396
- let items: User[] = getUsers()
397
- const total = items.length
398
-
399
- if (sortBy && sortBy.length > 0) {
400
- items = items.sort((a, b) => {
401
- const key = sortBy[0].key
402
- const order = sortBy[0].order === 'asc' ? 1 : -1
403
-
404
- return a[key] > b[key] ? order : -order
405
- })
406
- }
407
-
408
- if (itemsPerPage > 0) {
409
- items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
410
- }
411
-
412
- resolve({ items, total })
413
- state.value = StateEnum.RESOLVED
414
- })
415
- }
416
-
417
- const getUsers = (): User[] => {
418
- return [
419
- { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
420
- { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
421
- { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
422
- { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
423
- { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
424
- { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
425
- { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
426
- { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
427
- { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
428
- { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
429
- ]
430
- }
431
- </script>
432
- `,
375
+ <script setup lang="ts">
376
+ import { ref } from 'vue'
377
+ import { SyServerTable } from '@cnamts/synapse'
378
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
379
+ import type { DataOptions } from '@cnamts/synapse/src/components/Tables/common/types'
380
+
381
+ interface User {
382
+ [key: string]: string
383
+ firstname: string
384
+ lastname: string
385
+ email: string
386
+ }
387
+
388
+ interface DataObj {
389
+ items: User[]
390
+ total: number
391
+ }
392
+
393
+ const totalUsers = ref(0)
394
+ const users = ref<User[]>([])
395
+ const state = ref(StateEnum.IDLE)
396
+
397
+ const options = ref<DataOptions>({
398
+ itemsPerPage: 5,
399
+ sortBy: [{ key: 'lastname', order: 'desc' }],
400
+ page: 1,
401
+ })
402
+
403
+ const headers = [
404
+ { title: 'Nom', key: 'lastname' },
405
+ { title: 'Prénom', key: 'firstname' },
406
+ { title: 'Email', key: 'email' },
407
+ ]
408
+
409
+ const fetchData = async (): Promise<void> => {
410
+ const { items, total } = await getDataFromApi(options.value)
411
+ users.value = items
412
+ totalUsers.value = total
413
+ }
414
+
415
+ const wait = async (ms: number) => {
416
+ return new Promise(resolve => setTimeout(resolve, ms))
417
+ }
418
+
419
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise<DataObj> => {
420
+ state.value = StateEnum.PENDING
421
+ await wait(1000)
422
+
423
+ return new Promise((resolve) => {
424
+ let items: User[] = getUsers()
425
+ const total = items.length
426
+
427
+ if (sortBy && sortBy.length > 0) {
428
+ items = items.sort((a, b) => {
429
+ const key = sortBy[0].key
430
+ const order = sortBy[0].order === 'asc' ? 1 : -1
431
+
432
+ return a[key] > b[key] ? order : -order
433
+ })
434
+ }
435
+
436
+ if (itemsPerPage > 0) {
437
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
438
+ }
439
+
440
+ resolve({ items, total })
441
+ state.value = StateEnum.RESOLVED
442
+ })
443
+ }
444
+
445
+ const getUsers = (): User[] => {
446
+ return [
447
+ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
448
+ { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
449
+ { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
450
+ { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
451
+ { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
452
+ { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
453
+ { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
454
+ { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
455
+ { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
456
+ { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
457
+ { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' },
458
+ { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' },
459
+ { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' },
460
+ { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' },
461
+ { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' },
462
+ ]
463
+ }
464
+
465
+ // Initialize data
466
+ fetchData()
467
+ </script>
468
+ `,
433
469
  },
434
470
  ],
435
471
  },
436
472
  args: {
437
- options: {
473
+ 'options': {
438
474
  itemsPerPage: 5,
439
475
  sortBy: [{ key: 'lastname', order: 'desc' }],
440
476
  page: 1,
441
477
  },
442
- headers: [
478
+ 'headers': [
443
479
  { title: 'Nom', key: 'lastname' },
444
480
  { title: 'Prénom', key: 'firstname' },
445
481
  { title: 'Email', key: 'email' },
446
482
  ],
447
- caption: '',
448
- serverItemsLength: 0,
449
- suffix: 'server-sort',
450
- density: 'default',
451
- striped: false,
483
+ 'caption': '',
484
+ 'serverItemsLength': 15,
485
+ 'suffix': 'server-sort',
486
+ 'density': 'default',
487
+ 'striped': false,
488
+ 'onUpdate:options': fn(),
452
489
  },
453
490
  render: (args) => {
454
491
  return {
@@ -458,8 +495,16 @@ export const ServerSortBy: Story = {
458
495
  const users = ref<User[]>([])
459
496
  const state = ref(StateEnum.IDLE)
460
497
 
498
+ const options = ref({ ...args.options })
499
+
500
+ watch(options, (newVal) => {
501
+ if (args.options) {
502
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
503
+ }
504
+ }, { deep: true })
505
+
461
506
  const fetchData = async (): Promise<void> => {
462
- const { items, total } = await getDataFromApi(args.options as DataOptions)
507
+ const { items, total } = await getDataFromApi(options.value as DataOptions)
463
508
  users.value = items
464
509
  totalUsers.value = total
465
510
  }
@@ -506,28 +551,31 @@ export const ServerSortBy: Story = {
506
551
  { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
507
552
  { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
508
553
  { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
554
+ { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' },
555
+ { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' },
556
+ { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' },
557
+ { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' },
558
+ { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' },
509
559
  ]
510
560
  }
511
561
 
512
- return { args, users, state, fetchData, totalUsers, StateEnum }
562
+ // Initialize data
563
+ fetchData()
564
+
565
+ return { args, users, state, fetchData, options, totalUsers, StateEnum }
513
566
  },
514
567
  template: `
515
- <div>
516
- <SyServerTable
517
- v-model:options="args.options"
518
- :items="users"
519
- :headers="args.headers"
520
- :caption="args.caption"
521
- :server-items-length="totalUsers"
522
- :loading="state === StateEnum.PENDING"
523
- :suffix="args.suffix"
524
- :density="args.density"
525
- :striped="args.striped"
526
- :resizable-columns="args.resizableColumns"
527
- @update:options="fetchData"
528
- />
529
- </div>
530
- `,
568
+ <div>
569
+ <SyServerTable
570
+ v-model:options="options"
571
+ :items="users"
572
+ :server-items-length="totalUsers"
573
+ :loading="state === StateEnum.PENDING"
574
+ v-bind="args"
575
+ @update:options="fetchData"
576
+ />
577
+ </div>
578
+ `,
531
579
  }
532
580
  },
533
581
  }
@@ -538,153 +586,153 @@ export const ServerFilterByText: Story = {
538
586
  {
539
587
  name: 'Template',
540
588
  code: `
541
- <template>
542
- <SyServerTable
543
- v-model:options="options"
544
- :items="filteredUsers"
545
- :headers="headers"
546
- :server-items-length="totalFilteredUsers"
547
- :loading="state === StateEnum.PENDING"
548
- suffix="server-filter-text"
549
- :show-filters="true"
550
- @update:options="fetchData"
551
- />
552
- </template>
553
- `,
589
+ <template>
590
+ <SyServerTable
591
+ v-model:options="options"
592
+ :items="filteredUsers"
593
+ :headers="headers"
594
+ :server-items-length="totalFilteredUsers"
595
+ :loading="state === StateEnum.PENDING"
596
+ suffix="server-filter-text"
597
+ :show-filters="true"
598
+ @update:options="fetchData"
599
+ />
600
+ </template>
601
+ `,
554
602
  },
555
603
  {
556
604
  name: 'Script',
557
605
  code: `
558
- <script setup lang="ts">
559
- import { ref } from 'vue'
560
- import { SyServerTable } from '@cnamts/synapse'
561
- import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
562
- import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
563
-
564
- interface User {
565
- firstname: string
566
- lastname: string
567
- email: string
568
- }
569
-
570
- interface DataObj {
571
- items: User[]
572
- total: number
573
- }
574
-
575
- const totalFilteredUsers = ref(0)
576
- const filteredUsers = ref<User[]>([])
577
- const state = ref(StateEnum.IDLE)
578
-
579
- const options = ref<DataOptions>({
580
- itemsPerPage: 5,
581
- page: 1,
582
- filters: [],
583
- })
584
-
585
- const headers = [
586
- {
587
- title: 'Prénom',
588
- key: 'firstname',
589
- filterable: true,
590
- filterType: 'text'
591
- },
592
- {
593
- title: 'Nom',
594
- key: 'lastname',
595
- filterable: true,
596
- filterType: 'text'
597
- },
598
- {
599
- title: 'Email',
600
- key: 'email',
601
- filterable: true,
602
- filterType: 'text'
603
- }
604
- ]
605
-
606
- const fetchData = async (): Promise<void> => {
607
- const { items, total } = await getDataFromApi(options.value)
608
- filteredUsers.value = items
609
- totalFilteredUsers.value = total
610
- }
611
-
612
- const wait = async (ms: number) => {
613
- return new Promise(resolve => setTimeout(resolve, ms))
614
- }
615
-
616
- const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
617
- state.value = StateEnum.PENDING
618
- await wait(1000)
619
-
620
- return new Promise((resolve) => {
621
- // Get all users
622
- let items: User[] = getUsers()
623
-
624
- // Apply filters on server side
625
- if (filters && filters.length > 0) {
626
- filters.forEach((filter: FilterOption) => {
627
- const { key, value } = filter
628
-
629
- items = items.filter(item => {
630
- const itemValue = item[key as keyof User]
631
- return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
632
- })
633
- })
634
- }
635
-
636
- const total = items.length
637
-
638
- // Apply sorting
639
- if (sortBy && sortBy.length > 0) {
640
- items = items.sort((a, b) => {
641
- const key = sortBy[0].key as keyof User
642
- const order = sortBy[0].order === 'asc' ? 1 : -1
643
-
644
- return String(a[key]) > String(b[key]) ? order : -order
645
- })
646
- }
647
-
648
- // Apply pagination
649
- if (itemsPerPage > 0) {
650
- items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
651
- }
652
-
653
- resolve({ items, total })
654
- state.value = StateEnum.RESOLVED
655
- })
656
- }
657
-
658
- const getUsers = (): User[] => {
659
- return [
660
- { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
661
- { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
662
- { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
663
- { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
664
- { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
665
- { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
666
- { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
667
- { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
668
- { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
669
- { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
670
- { firstname: 'Martin', lastname: 'Lavoie', email: 'martin.lavoie@example.com' },
671
- { firstname: 'Céline', lastname: 'Tremblay', email: 'celine.tremblay@example.com' },
672
- { firstname: 'Jacques', lastname: 'Gagnon', email: 'jacques.gagnon@example.com' },
673
- { firstname: 'Isabelle', lastname: 'Côté', email: 'isabelle.cote@example.com' },
674
- { firstname: 'Philippe', lastname: 'Bouchard', email: 'philippe.bouchard@example.com' },
675
- ]
676
- }
677
-
678
- // Initialize data
679
- fetchData()
680
- </script>
681
- `,
606
+ <script setup lang="ts">
607
+ import { ref } from 'vue'
608
+ import { SyServerTable } from '@cnamts/synapse'
609
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
610
+ import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
611
+
612
+ interface User {
613
+ firstname: string
614
+ lastname: string
615
+ email: string
616
+ }
617
+
618
+ interface DataObj {
619
+ items: User[]
620
+ total: number
621
+ }
622
+
623
+ const totalFilteredUsers = ref(0)
624
+ const filteredUsers = ref<User[]>([])
625
+ const state = ref(StateEnum.IDLE)
626
+
627
+ const options = ref<DataOptions>({
628
+ itemsPerPage: 5,
629
+ page: 1,
630
+ filters: [],
631
+ })
632
+
633
+ const headers = [
634
+ {
635
+ title: 'Prénom',
636
+ key: 'firstname',
637
+ filterable: true,
638
+ filterType: 'text'
639
+ },
640
+ {
641
+ title: 'Nom',
642
+ key: 'lastname',
643
+ filterable: true,
644
+ filterType: 'text'
645
+ },
646
+ {
647
+ title: 'Email',
648
+ key: 'email',
649
+ filterable: true,
650
+ filterType: 'text'
651
+ }
652
+ ]
653
+
654
+ const fetchData = async (): Promise<void> => {
655
+ const { items, total } = await getDataFromApi(options.value)
656
+ filteredUsers.value = items
657
+ totalFilteredUsers.value = total
658
+ }
659
+
660
+ const wait = async (ms: number) => {
661
+ return new Promise(resolve => setTimeout(resolve, ms))
662
+ }
663
+
664
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
665
+ state.value = StateEnum.PENDING
666
+ await wait(1000)
667
+
668
+ return new Promise((resolve) => {
669
+ // Get all users
670
+ let items: User[] = getUsers()
671
+
672
+ // Apply filters on server side
673
+ if (filters && filters.length > 0) {
674
+ filters.forEach((filter: FilterOption) => {
675
+ const { key, value } = filter
676
+
677
+ items = items.filter(item => {
678
+ const itemValue = item[key as keyof User]
679
+ return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
680
+ })
681
+ })
682
+ }
683
+
684
+ const total = items.length
685
+
686
+ // Apply sorting
687
+ if (sortBy && sortBy.length > 0) {
688
+ items = items.sort((a, b) => {
689
+ const key = sortBy[0].key as keyof User
690
+ const order = sortBy[0].order === 'asc' ? 1 : -1
691
+
692
+ return String(a[key]) > String(b[key]) ? order : -order
693
+ })
694
+ }
695
+
696
+ // Apply pagination
697
+ if (itemsPerPage > 0) {
698
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
699
+ }
700
+
701
+ resolve({ items, total })
702
+ state.value = StateEnum.RESOLVED
703
+ })
704
+ }
705
+
706
+ const getUsers = (): User[] => {
707
+ return [
708
+ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
709
+ { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
710
+ { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
711
+ { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
712
+ { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
713
+ { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
714
+ { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
715
+ { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
716
+ { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
717
+ { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
718
+ { firstname: 'Martin', lastname: 'Lavoie', email: 'martin.lavoie@example.com' },
719
+ { firstname: 'Céline', lastname: 'Tremblay', email: 'celine.tremblay@example.com' },
720
+ { firstname: 'Jacques', lastname: 'Gagnon', email: 'jacques.gagnon@example.com' },
721
+ { firstname: 'Isabelle', lastname: 'Côté', email: 'isabelle.cote@example.com' },
722
+ { firstname: 'Philippe', lastname: 'Bouchard', email: 'philippe.bouchard@example.com' },
723
+ ]
724
+ }
725
+
726
+ // Initialize data
727
+ fetchData()
728
+ </script>
729
+ `,
682
730
  },
683
731
  ],
684
732
  },
685
733
  args: {
686
- serverItemsLength: 15,
687
- headers: [
734
+ 'serverItemsLength': 15,
735
+ 'headers': [
688
736
  {
689
737
  title: 'Prénom',
690
738
  key: 'firstname',
@@ -704,22 +752,30 @@ export const ServerFilterByText: Story = {
704
752
  filterType: 'text',
705
753
  },
706
754
  ],
707
- caption: '',
708
- options: {
755
+ 'caption': '',
756
+ 'options': {
709
757
  itemsPerPage: 5,
710
758
  page: 1,
711
759
  filters: [],
712
760
  },
713
- showFilters: true,
714
- suffix: 'server-filter-text',
715
- density: 'default',
716
- striped: false,
761
+ 'showFilters': true,
762
+ 'suffix': 'server-filter-text',
763
+ 'density': 'default',
764
+ 'striped': false,
765
+ 'onUpdate:options': fn(),
717
766
  },
718
767
  render(args) {
719
768
  return {
720
769
  components: { SyServerTable },
721
770
  setup() {
722
- const options = ref(args.options)
771
+ const options = ref({ ...args.options })
772
+
773
+ watch(options, (newVal) => {
774
+ if (args.options) {
775
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
776
+ }
777
+ }, { deep: true })
778
+
723
779
  const totalFilteredUsers = ref(0)
724
780
  const filteredUsers = ref<Record<string, unknown>[]>([])
725
781
  const state = ref(StateEnum.IDLE)
@@ -779,10 +835,10 @@ export const ServerFilterByText: Story = {
779
835
 
780
836
  return {
781
837
  args,
782
- options,
783
838
  filteredUsers,
784
839
  totalFilteredUsers,
785
840
  state,
841
+ options,
786
842
  fetchData,
787
843
  StateEnum,
788
844
  }
@@ -790,17 +846,12 @@ export const ServerFilterByText: Story = {
790
846
  template: `
791
847
  <div>
792
848
  <SyServerTable
849
+ v-bind="args"
793
850
  v-model:options="options"
794
851
  :items="filteredUsers"
795
- :headers="args.headers"
796
- :caption="args.caption"
797
852
  :server-items-length="totalFilteredUsers"
798
853
  :loading="state === StateEnum.PENDING"
799
- :show-filters="args.showFilters"
800
- :suffix="args.suffix"
801
- :density="args.density"
802
- :striped="args.striped"
803
- :resizable-columns="args.resizableColumns"
854
+ suffix="server-filter-text"
804
855
  @update:options="fetchData"
805
856
  />
806
857
  </div>
@@ -815,161 +866,161 @@ export const ServerFilterByNumber: Story = {
815
866
  {
816
867
  name: 'Template',
817
868
  code: `
818
- <template>
819
- <SyServerTable
820
- v-model:options="options"
821
- :items="filteredUsers"
822
- :headers="headers"
823
- :server-items-length="totalFilteredUsers"
824
- :loading="state === StateEnum.PENDING"
825
- suffix="server-filter-number"
826
- :show-filters="true"
827
- @update:options="fetchData"
828
- />
829
- </template>
830
- `,
869
+ <template>
870
+ <SyServerTable
871
+ v-model:options="options"
872
+ :items="filteredUsers"
873
+ :headers="headers"
874
+ :server-items-length="totalFilteredUsers"
875
+ :loading="state === StateEnum.PENDING"
876
+ suffix="server-filter-number"
877
+ :show-filters="true"
878
+ @update:options="fetchData"
879
+ />
880
+ </template>
881
+ `,
831
882
  },
832
883
  {
833
884
  name: 'Script',
834
885
  code: `
835
- <script setup lang="ts">
836
- import { ref } from 'vue'
837
- import { SyServerTable } from '@cnamts/synapse'
838
- import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
839
- import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
840
-
841
- interface User {
842
- name: string
843
- age: number
844
- salary: number
845
- }
846
-
847
- interface DataObj {
848
- items: User[]
849
- total: number
850
- }
851
-
852
- const totalFilteredUsers = ref(0)
853
- const filteredUsers = ref<User[]>([])
854
- const state = ref(StateEnum.IDLE)
855
-
856
- const options = ref<DataOptions>({
857
- itemsPerPage: 5,
858
- page: 1,
859
- filters: [],
860
- })
861
-
862
- const headers = [
863
- {
864
- title: 'Nom',
865
- key: 'name',
866
- filterable: true,
867
- filterType: 'text'
868
- },
869
- {
870
- title: 'Âge',
871
- key: 'age',
872
- filterable: true,
873
- filterType: 'number'
874
- },
875
- {
876
- title: 'Salaire',
877
- key: 'salary',
878
- filterable: true,
879
- filterType: 'number'
880
- }
881
- ]
882
-
883
- const fetchData = async (): Promise<void> => {
884
- const { items, total } = await getDataFromApi(options.value)
885
- filteredUsers.value = items
886
- totalFilteredUsers.value = total
887
- }
888
-
889
- const wait = async (ms: number) => {
890
- return new Promise(resolve => setTimeout(resolve, ms))
891
- }
892
-
893
- const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
894
- state.value = StateEnum.PENDING
895
- await wait(1000)
896
-
897
- return new Promise((resolve) => {
898
- // Get all users
899
- let items: User[] = getUsers()
900
-
901
- // Apply filters on server side
902
- if (filters && filters.length > 0) {
903
- filters.forEach((filter: FilterOption) => {
904
- const { key, value, type } = filter
905
-
906
- items = items.filter(item => {
907
- const itemValue = item[key as keyof User]
908
-
909
- if (type === 'number') {
910
- return Number(itemValue) === Number(value)
911
- } else {
912
- return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
913
- }
914
- })
915
- })
916
- }
917
-
918
- const total = items.length
919
-
920
- // Apply sorting
921
- if (sortBy && sortBy.length > 0) {
922
- items = items.sort((a, b) => {
923
- const key = sortBy[0].key as keyof User
924
- const order = sortBy[0].order === 'asc' ? 1 : -1
925
-
926
- if (typeof a[key] === 'number' && typeof b[key] === 'number') {
927
- return (a[key] as number) > (b[key] as number) ? order : -order
928
- }
929
-
930
- return String(a[key]) > String(b[key]) ? order : -order
931
- })
932
- }
933
-
934
- // Apply pagination
935
- if (itemsPerPage > 0) {
936
- items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
937
- }
938
-
939
- resolve({ items, total })
940
- state.value = StateEnum.RESOLVED
941
- })
942
- }
943
-
944
- const getUsers = (): User[] => {
945
- return [
946
- { name: 'Jean Dupont', age: 32, salary: 45000 },
947
- { name: 'Marie Martin', age: 28, salary: 52000 },
948
- { name: 'Pierre Durand', age: 45, salary: 65000 },
949
- { name: 'Sophie Petit', age: 36, salary: 48000 },
950
- { name: 'Thomas Leroy', age: 41, salary: 58000 },
951
- { name: 'Julie Bernard', age: 29, salary: 47000 },
952
- { name: 'Nicolas Moreau', age: 38, salary: 61000 },
953
- { name: 'Camille Dubois', age: 33, salary: 49000 },
954
- { name: 'Alexandre Lefebvre', age: 44, salary: 67000 },
955
- { name: 'Émilie Girard', age: 31, salary: 51000 },
956
- { name: 'Lucas Roux', age: 39, salary: 59000 },
957
- { name: 'Chloé Lambert', age: 27, salary: 46000 },
958
- { name: 'Maxime Simon', age: 42, salary: 63000 },
959
- { name: 'Laura Fournier', age: 35, salary: 54000 },
960
- { name: 'Antoine Mercier', age: 40, salary: 60000 },
961
- ]
962
- }
963
-
964
- // Initialize data
965
- fetchData()
966
- </script>
967
- `,
886
+ <script setup lang="ts">
887
+ import { ref } from 'vue'
888
+ import { SyServerTable } from '@cnamts/synapse'
889
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
890
+ import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
891
+
892
+ interface User {
893
+ name: string
894
+ age: number
895
+ salary: number
896
+ }
897
+
898
+ interface DataObj {
899
+ items: User[]
900
+ total: number
901
+ }
902
+
903
+ const totalFilteredUsers = ref(0)
904
+ const filteredUsers = ref<User[]>([])
905
+ const state = ref(StateEnum.IDLE)
906
+
907
+ const options = ref<DataOptions>({
908
+ itemsPerPage: 5,
909
+ page: 1,
910
+ filters: [],
911
+ })
912
+
913
+ const headers = [
914
+ {
915
+ title: 'Nom',
916
+ key: 'name',
917
+ filterable: true,
918
+ filterType: 'text'
919
+ },
920
+ {
921
+ title: 'Âge',
922
+ key: 'age',
923
+ filterable: true,
924
+ filterType: 'number'
925
+ },
926
+ {
927
+ title: 'Salaire',
928
+ key: 'salary',
929
+ filterable: true,
930
+ filterType: 'number'
931
+ }
932
+ ]
933
+
934
+ const fetchData = async (): Promise<void> => {
935
+ const { items, total } = await getDataFromApi(options.value)
936
+ filteredUsers.value = items
937
+ totalFilteredUsers.value = total
938
+ }
939
+
940
+ const wait = async (ms: number) => {
941
+ return new Promise(resolve => setTimeout(resolve, ms))
942
+ }
943
+
944
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
945
+ state.value = StateEnum.PENDING
946
+ await wait(1000)
947
+
948
+ return new Promise((resolve) => {
949
+ // Get all users
950
+ let items: User[] = getUsers()
951
+
952
+ // Apply filters on server side
953
+ if (filters && filters.length > 0) {
954
+ filters.forEach((filter: FilterOption) => {
955
+ const { key, value, type } = filter
956
+
957
+ items = items.filter(item => {
958
+ const itemValue = item[key as keyof User]
959
+
960
+ if (type === 'number') {
961
+ return Number(itemValue) === Number(value)
962
+ } else {
963
+ return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
964
+ }
965
+ })
966
+ })
967
+ }
968
+
969
+ const total = items.length
970
+
971
+ // Apply sorting
972
+ if (sortBy && sortBy.length > 0) {
973
+ items = items.sort((a, b) => {
974
+ const key = sortBy[0].key as keyof User
975
+ const order = sortBy[0].order === 'asc' ? 1 : -1
976
+
977
+ if (typeof a[key] === 'number' && typeof b[key] === 'number') {
978
+ return (a[key] as number) > (b[key] as number) ? order : -order
979
+ }
980
+
981
+ return String(a[key]) > String(b[key]) ? order : -order
982
+ })
983
+ }
984
+
985
+ // Apply pagination
986
+ if (itemsPerPage > 0) {
987
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
988
+ }
989
+
990
+ resolve({ items, total })
991
+ state.value = StateEnum.RESOLVED
992
+ })
993
+ }
994
+
995
+ const getUsers = (): User[] => {
996
+ return [
997
+ { name: 'Jean Dupont', age: 32, salary: 45000 },
998
+ { name: 'Marie Martin', age: 28, salary: 52000 },
999
+ { name: 'Pierre Durand', age: 45, salary: 65000 },
1000
+ { name: 'Sophie Petit', age: 36, salary: 48000 },
1001
+ { name: 'Thomas Leroy', age: 41, salary: 58000 },
1002
+ { name: 'Julie Bernard', age: 29, salary: 47000 },
1003
+ { name: 'Nicolas Moreau', age: 38, salary: 61000 },
1004
+ { name: 'Camille Dubois', age: 33, salary: 49000 },
1005
+ { name: 'Alexandre Lefebvre', age: 44, salary: 67000 },
1006
+ { name: 'Émilie Girard', age: 31, salary: 51000 },
1007
+ { name: 'Lucas Roux', age: 39, salary: 59000 },
1008
+ { name: 'Chloé Lambert', age: 27, salary: 46000 },
1009
+ { name: 'Maxime Simon', age: 42, salary: 63000 },
1010
+ { name: 'Laura Fournier', age: 35, salary: 54000 },
1011
+ { name: 'Antoine Mercier', age: 40, salary: 60000 },
1012
+ ]
1013
+ }
1014
+
1015
+ // Initialize data
1016
+ fetchData()
1017
+ </script>
1018
+ `,
968
1019
  },
969
1020
  ],
970
1021
  },
971
1022
  args: {
972
- headers: [
1023
+ 'headers': [
973
1024
  {
974
1025
  title: 'Nom',
975
1026
  key: 'name',
@@ -989,23 +1040,31 @@ export const ServerFilterByNumber: Story = {
989
1040
  filterType: 'number',
990
1041
  },
991
1042
  ],
992
- caption: '',
993
- options: {
1043
+ 'caption': '',
1044
+ 'options': {
994
1045
  itemsPerPage: 5,
995
1046
  page: 1,
996
1047
  filters: [],
997
1048
  },
998
- serverItemsLength: 15,
999
- showFilters: true,
1000
- suffix: 'server-filter-number',
1001
- density: 'default',
1002
- striped: false,
1049
+ 'serverItemsLength': 15,
1050
+ 'showFilters': true,
1051
+ 'suffix': 'server-filter-number',
1052
+ 'density': 'default',
1053
+ 'striped': false,
1054
+ 'onUpdate:options': fn(),
1003
1055
  },
1004
1056
  render(args) {
1005
1057
  return {
1006
1058
  components: { SyServerTable },
1007
1059
  setup() {
1008
- const options = ref(args.options)
1060
+ const options = ref({ ...args.options })
1061
+
1062
+ watch(options, (newVal) => {
1063
+ if (args.options) {
1064
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
1065
+ }
1066
+ }, { deep: true })
1067
+
1009
1068
  const totalFilteredUsers = ref(0)
1010
1069
  const filteredUsers = ref<Record<string, unknown>[]>([])
1011
1070
  const state = ref(StateEnum.IDLE)
@@ -1071,9 +1130,9 @@ export const ServerFilterByNumber: Story = {
1071
1130
 
1072
1131
  return {
1073
1132
  args,
1074
- options,
1075
1133
  filteredUsers,
1076
1134
  totalFilteredUsers,
1135
+ options,
1077
1136
  state,
1078
1137
  fetchData,
1079
1138
  StateEnum,
@@ -1082,17 +1141,11 @@ export const ServerFilterByNumber: Story = {
1082
1141
  template: `
1083
1142
  <div>
1084
1143
  <SyServerTable
1144
+ v-bind="args"
1085
1145
  v-model:options="options"
1086
1146
  :items="filteredUsers"
1087
- :headers="args.headers"
1088
- :caption="args.caption"
1089
1147
  :server-items-length="totalFilteredUsers"
1090
1148
  :loading="state === StateEnum.PENDING"
1091
- :show-filters="args.showFilters"
1092
- :suffix="args.suffix"
1093
- :density="args.density"
1094
- :striped="args.striped"
1095
- :resizable-columns="args.resizableColumns"
1096
1149
  @update:options="fetchData"
1097
1150
  />
1098
1151
  </div>
@@ -1107,170 +1160,170 @@ export const ServerFilterBySelect: Story = {
1107
1160
  {
1108
1161
  name: 'Template',
1109
1162
  code: `
1110
- <template>
1111
- <SyServerTable
1112
- v-model:options="options"
1113
- :items="filteredUsers"
1114
- :headers="headers"
1115
- :server-items-length="totalFilteredUsers"
1116
- :loading="state === StateEnum.PENDING"
1117
- suffix="server-filter-select"
1118
- :show-filters="true"
1119
- @update:options="fetchData"
1120
- />
1121
- </template>
1122
- `,
1163
+ <template>
1164
+ <SyServerTable
1165
+ v-model:options="options"
1166
+ :items="filteredUsers"
1167
+ :headers="headers"
1168
+ :server-items-length="totalFilteredUsers"
1169
+ :loading="state === StateEnum.PENDING"
1170
+ suffix="server-filter-select"
1171
+ :show-filters="true"
1172
+ @update:options="fetchData"
1173
+ />
1174
+ </template>
1175
+ `,
1123
1176
  },
1124
1177
  {
1125
1178
  name: 'Script',
1126
1179
  code: `
1127
- <script setup lang="ts">
1128
- import { ref } from 'vue'
1129
- import { SyServerTable } from '@cnamts/synapse'
1130
- import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
1131
- import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
1132
-
1133
- interface User {
1134
- name: string
1135
- department: string
1136
- status: string
1137
- }
1138
-
1139
- interface DataObj {
1140
- items: User[]
1141
- total: number
1142
- }
1143
-
1144
- const totalFilteredUsers = ref(0)
1145
- const filteredUsers = ref<User[]>([])
1146
- const state = ref(StateEnum.IDLE)
1147
-
1148
- const options = ref<DataOptions>({
1149
- itemsPerPage: 5,
1150
- page: 1,
1151
- filters: [],
1152
- })
1153
-
1154
- const headers = [
1155
- {
1156
- title: 'Nom',
1157
- key: 'name',
1158
- filterable: true,
1159
- filterType: 'text'
1160
- },
1161
- {
1162
- title: 'Département',
1163
- key: 'department',
1164
- filterable: true,
1165
- filterType: 'select',
1166
- hideMessages: true,
1167
- filterOptions: [
1168
- { text: 'RH', value: 'RH' },
1169
- { text: 'IT', value: 'IT' },
1170
- { text: 'Finance', value: 'Finance' },
1171
- { text: 'Marketing', value: 'Marketing' },
1172
- ]
1173
- },
1174
- {
1175
- title: 'Statut',
1176
- key: 'status',
1177
- filterable: true,
1178
- filterType: 'select',
1179
- hideMessages: true,
1180
- filterOptions: [
1181
- { text: 'Actif', value: 'Actif' },
1182
- { text: 'En congé', value: 'En congé' },
1183
- { text: 'Inactif', value: 'Inactif' },
1184
- ]
1185
- }
1186
- ]
1187
-
1188
- const fetchData = async (): Promise<void> => {
1189
- const { items, total } = await getDataFromApi(options.value)
1190
- filteredUsers.value = items
1191
- totalFilteredUsers.value = total
1192
- }
1193
-
1194
- const wait = async (ms: number) => {
1195
- return new Promise(resolve => setTimeout(resolve, ms))
1196
- }
1197
-
1198
- const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
1199
- state.value = StateEnum.PENDING
1200
- await wait(1000)
1201
-
1202
- return new Promise((resolve) => {
1203
- // Get all users
1204
- let items: User[] = getUsers()
1205
-
1206
- // Apply filters on server side
1207
- if (filters && filters.length > 0) {
1208
- filters.forEach((filter: FilterOption) => {
1209
- const { key, value, type } = filter
1210
-
1211
- items = items.filter(item => {
1212
- const itemValue = item[key as keyof User]
1213
-
1214
- if (type === 'select') {
1215
- return itemValue === value
1216
- } else {
1217
- return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
1218
- }
1219
- })
1220
- })
1221
- }
1222
-
1223
- const total = items.length
1224
-
1225
- // Apply sorting
1226
- if (sortBy && sortBy.length > 0) {
1227
- items = items.sort((a, b) => {
1228
- const key = sortBy[0].key as keyof User
1229
- const order = sortBy[0].order === 'asc' ? 1 : -1
1230
-
1231
- return String(a[key]) > String(b[key]) ? order : -order
1232
- })
1233
- }
1234
-
1235
- // Apply pagination
1236
- if (itemsPerPage > 0) {
1237
- items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
1238
- }
1239
-
1240
- resolve({ items, total })
1241
- state.value = StateEnum.RESOLVED
1242
- })
1243
- }
1244
-
1245
- const getUsers = (): User[] => {
1246
- return [
1247
- { name: 'Jean Dupont', department: 'RH', status: 'Actif' },
1248
- { name: 'Marie Martin', department: 'IT', status: 'En congé' },
1249
- { name: 'Pierre Durand', department: 'Finance', status: 'Actif' },
1250
- { name: 'Sophie Petit', department: 'Marketing', status: 'Actif' },
1251
- { name: 'Thomas Leroy', department: 'IT', status: 'Inactif' },
1252
- { name: 'Julie Bernard', department: 'RH', status: 'Actif' },
1253
- { name: 'Nicolas Moreau', department: 'Finance', status: 'En congé' },
1254
- { name: 'Camille Dubois', department: 'Marketing', status: 'Inactif' },
1255
- { name: 'Alexandre Lefebvre', department: 'IT', status: 'Actif' },
1256
- { name: 'Émilie Girard', department: 'RH', status: 'En congé' },
1257
- { name: 'Lucas Roux', department: 'Finance', status: 'Actif' },
1258
- { name: 'Chloé Lambert', department: 'Marketing', status: 'Actif' },
1259
- { name: 'Maxime Simon', department: 'IT', status: 'Inactif' },
1260
- { name: 'Laura Fournier', department: 'RH', status: 'Actif' },
1261
- { name: 'Antoine Mercier', department: 'Finance', status: 'En congé' },
1262
- ]
1263
- }
1264
-
1265
- // Initialize data
1266
- fetchData()
1267
- </script>
1268
- `,
1180
+ <script setup lang="ts">
1181
+ import { ref } from 'vue'
1182
+ import { SyServerTable } from '@cnamts/synapse'
1183
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
1184
+ import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
1185
+
1186
+ interface User {
1187
+ name: string
1188
+ department: string
1189
+ status: string
1190
+ }
1191
+
1192
+ interface DataObj {
1193
+ items: User[]
1194
+ total: number
1195
+ }
1196
+
1197
+ const totalFilteredUsers = ref(0)
1198
+ const filteredUsers = ref<User[]>([])
1199
+ const state = ref(StateEnum.IDLE)
1200
+
1201
+ const options = ref<DataOptions>({
1202
+ itemsPerPage: 5,
1203
+ page: 1,
1204
+ filters: [],
1205
+ })
1206
+
1207
+ const headers = [
1208
+ {
1209
+ title: 'Nom',
1210
+ key: 'name',
1211
+ filterable: true,
1212
+ filterType: 'text'
1213
+ },
1214
+ {
1215
+ title: 'Département',
1216
+ key: 'department',
1217
+ filterable: true,
1218
+ filterType: 'select',
1219
+ hideMessages: true,
1220
+ filterOptions: [
1221
+ { text: 'RH', value: 'RH' },
1222
+ { text: 'IT', value: 'IT' },
1223
+ { text: 'Finance', value: 'Finance' },
1224
+ { text: 'Marketing', value: 'Marketing' },
1225
+ ]
1226
+ },
1227
+ {
1228
+ title: 'Statut',
1229
+ key: 'status',
1230
+ filterable: true,
1231
+ filterType: 'select',
1232
+ hideMessages: true,
1233
+ filterOptions: [
1234
+ { text: 'Actif', value: 'Actif' },
1235
+ { text: 'En congé', value: 'En congé' },
1236
+ { text: 'Inactif', value: 'Inactif' },
1237
+ ]
1238
+ }
1239
+ ]
1240
+
1241
+ const fetchData = async (): Promise<void> => {
1242
+ const { items, total } = await getDataFromApi(options.value)
1243
+ filteredUsers.value = items
1244
+ totalFilteredUsers.value = total
1245
+ }
1246
+
1247
+ const wait = async (ms: number) => {
1248
+ return new Promise(resolve => setTimeout(resolve, ms))
1249
+ }
1250
+
1251
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
1252
+ state.value = StateEnum.PENDING
1253
+ await wait(1000)
1254
+
1255
+ return new Promise((resolve) => {
1256
+ // Get all users
1257
+ let items: User[] = getUsers()
1258
+
1259
+ // Apply filters on server side
1260
+ if (filters && filters.length > 0) {
1261
+ filters.forEach((filter: FilterOption) => {
1262
+ const { key, value, type } = filter
1263
+
1264
+ items = items.filter(item => {
1265
+ const itemValue = item[key as keyof User]
1266
+
1267
+ if (type === 'select') {
1268
+ return itemValue === value
1269
+ } else {
1270
+ return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
1271
+ }
1272
+ })
1273
+ })
1274
+ }
1275
+
1276
+ const total = items.length
1277
+
1278
+ // Apply sorting
1279
+ if (sortBy && sortBy.length > 0) {
1280
+ items = items.sort((a, b) => {
1281
+ const key = sortBy[0].key as keyof User
1282
+ const order = sortBy[0].order === 'asc' ? 1 : -1
1283
+
1284
+ return String(a[key]) > String(b[key]) ? order : -order
1285
+ })
1286
+ }
1287
+
1288
+ // Apply pagination
1289
+ if (itemsPerPage > 0) {
1290
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
1291
+ }
1292
+
1293
+ resolve({ items, total })
1294
+ state.value = StateEnum.RESOLVED
1295
+ })
1296
+ }
1297
+
1298
+ const getUsers = (): User[] => {
1299
+ return [
1300
+ { name: 'Jean Dupont', department: 'RH', status: 'Actif' },
1301
+ { name: 'Marie Martin', department: 'IT', status: 'En congé' },
1302
+ { name: 'Pierre Durand', department: 'Finance', status: 'Actif' },
1303
+ { name: 'Sophie Petit', department: 'Marketing', status: 'Actif' },
1304
+ { name: 'Thomas Leroy', department: 'IT', status: 'Inactif' },
1305
+ { name: 'Julie Bernard', department: 'RH', status: 'Actif' },
1306
+ { name: 'Nicolas Moreau', department: 'Finance', status: 'En congé' },
1307
+ { name: 'Camille Dubois', department: 'Marketing', status: 'Inactif' },
1308
+ { name: 'Alexandre Lefebvre', department: 'IT', status: 'Actif' },
1309
+ { name: 'Émilie Girard', department: 'RH', status: 'En congé' },
1310
+ { name: 'Lucas Roux', department: 'Finance', status: 'Actif' },
1311
+ { name: 'Chloé Lambert', department: 'Marketing', status: 'Actif' },
1312
+ { name: 'Maxime Simon', department: 'IT', status: 'Inactif' },
1313
+ { name: 'Laura Fournier', department: 'RH', status: 'Actif' },
1314
+ { name: 'Antoine Mercier', department: 'Finance', status: 'En congé' },
1315
+ ]
1316
+ }
1317
+
1318
+ // Initialize data
1319
+ fetchData()
1320
+ </script>
1321
+ `,
1269
1322
  },
1270
1323
  ],
1271
1324
  },
1272
1325
  args: {
1273
- headers: [
1326
+ 'headers': [
1274
1327
  {
1275
1328
  title: 'Nom',
1276
1329
  key: 'name',
@@ -1303,23 +1356,31 @@ export const ServerFilterBySelect: Story = {
1303
1356
  ],
1304
1357
  },
1305
1358
  ],
1306
- caption: '',
1307
- options: {
1359
+ 'caption': '',
1360
+ 'options': {
1308
1361
  itemsPerPage: 5,
1309
1362
  page: 1,
1310
1363
  filters: [],
1311
1364
  },
1312
- serverItemsLength: 15,
1313
- showFilters: true,
1314
- suffix: 'server-filter-select',
1315
- density: 'default',
1316
- striped: false,
1365
+ 'serverItemsLength': 15,
1366
+ 'showFilters': true,
1367
+ 'suffix': 'server-filter-select',
1368
+ 'density': 'default',
1369
+ 'striped': false,
1370
+ 'onUpdate:options': fn(),
1317
1371
  },
1318
1372
  render(args) {
1319
1373
  return {
1320
1374
  components: { SyServerTable },
1321
1375
  setup() {
1322
- const options = ref(args.options)
1376
+ const options = ref({ ...args.options })
1377
+
1378
+ watch(options, (newVal) => {
1379
+ if (args.options) {
1380
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
1381
+ }
1382
+ }, { deep: true })
1383
+
1323
1384
  const totalFilteredUsers = ref(0)
1324
1385
  const filteredUsers = ref<Record<string, unknown>[]>([])
1325
1386
  const state = ref(StateEnum.IDLE)
@@ -1385,9 +1446,9 @@ export const ServerFilterBySelect: Story = {
1385
1446
 
1386
1447
  return {
1387
1448
  args,
1388
- options,
1389
1449
  filteredUsers,
1390
1450
  totalFilteredUsers,
1451
+ options,
1391
1452
  state,
1392
1453
  fetchData,
1393
1454
  StateEnum,
@@ -1396,17 +1457,11 @@ export const ServerFilterBySelect: Story = {
1396
1457
  template: `
1397
1458
  <div>
1398
1459
  <SyServerTable
1460
+ v-bind="args"
1399
1461
  v-model:options="options"
1400
1462
  :items="filteredUsers"
1401
- :headers="args.headers"
1402
- :caption="args.caption"
1403
1463
  :server-items-length="totalFilteredUsers"
1404
1464
  :loading="state === StateEnum.PENDING"
1405
- :show-filters="args.showFilters"
1406
- :suffix="args.suffix"
1407
- :density="args.density"
1408
- :striped="args.striped"
1409
- :resizable-columns="args.resizableColumns"
1410
1465
  @update:options="fetchData"
1411
1466
  />
1412
1467
  </div>
@@ -1415,158 +1470,180 @@ export const ServerFilterBySelect: Story = {
1415
1470
  },
1416
1471
  }
1417
1472
 
1418
- export const ServerFilterByDate: Story = {
1473
+ export const ServerFilterBySelectMultiple: Story = {
1419
1474
  parameters: {
1420
1475
  sourceCode: [
1421
1476
  {
1422
1477
  name: 'Template',
1423
1478
  code: `
1424
- <template>
1425
- <SyServerTable
1426
- v-model:options="options"
1427
- :items="filteredUsers"
1428
- :headers="headers"
1429
- :server-items-length="totalFilteredUsers"
1430
- :loading="state === StateEnum.PENDING"
1431
- suffix="server-filter-date"
1432
- :show-filters="true"
1433
- @update:options="fetchData"
1434
- />
1435
- </template>
1436
- `,
1479
+ <template>
1480
+ <SyServerTable
1481
+ v-model:options="options"
1482
+ :items="filteredUsers"
1483
+ :headers="headers"
1484
+ :server-items-length="totalFilteredUsers"
1485
+ :loading="state === StateEnum.PENDING"
1486
+ suffix="server-filter-select"
1487
+ :show-filters="true"
1488
+ @update:options="fetchData"
1489
+ />
1490
+ </template>
1491
+ `,
1437
1492
  },
1438
1493
  {
1439
1494
  name: 'Script',
1440
1495
  code: `
1441
- <script setup lang="ts">
1442
- import { ref } from 'vue'
1443
- import { SyServerTable } from '@cnamts/synapse'
1444
- import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
1445
- import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
1446
-
1447
- interface User {
1448
- name: string
1449
- hireDate: string
1450
- vacationPeriod: {
1451
- from: string
1452
- to: string
1453
- }
1454
- }
1455
-
1456
- interface DataObj {
1457
- items: User[]
1458
- total: number
1459
- }
1460
-
1461
- const totalFilteredUsers = ref(0)
1462
- const filteredUsers = ref<User[]>([])
1463
- const state = ref(StateEnum.IDLE)
1464
-
1465
- const options = ref<DataOptions>({
1466
- itemsPerPage: 5,
1467
- page: 1,
1468
- filters: [],
1469
- })
1470
-
1471
- const headers = [
1472
- {
1473
- title: 'Nom',
1474
- key: 'name',
1475
- filterable: true,
1476
- filterType: 'text'
1477
- },
1478
- {
1479
- title: 'Date d'embauche',
1480
- key: 'hireDate',
1481
- filterable: true,
1482
- filterType: 'date',
1483
- dateFormat: 'DD/MM/YYYY'
1484
- },
1485
- {
1486
- title: 'Période de congés',
1487
- key: 'vacationPeriod',
1488
- filterable: true,
1489
- filterType: 'period',
1490
- dateFormat: 'DD/MM/YYYY'
1491
- }
1492
- ]
1493
-
1494
- const fetchData = async (): Promise<void> => {
1495
- const { items, total } = await getDataFromApi(options.value)
1496
- filteredUsers.value = items
1497
- totalFilteredUsers.value = total
1498
- }
1499
-
1500
- const wait = async (ms: number) => {
1501
- return new Promise(resolve => setTimeout(resolve, ms))
1502
- }
1503
-
1504
- const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
1505
- state.value = StateEnum.PENDING
1506
- await wait(1000)
1507
-
1508
- return new Promise((resolve) => {
1509
- // Get all users
1510
- let items: User[] = getUsers()
1511
-
1512
- // Apply filters on server side
1513
- if (filters && filters.length > 0) {
1514
- filters.forEach((filter: FilterOption) => {
1515
- const { key, value, type } = filter
1516
-
1517
- items = items.filter(item => {
1518
- const itemValue = item[key as keyof User]
1519
-
1520
- if (type === 'date') {
1521
- // Simple date comparison for demo purposes
1522
- return itemValue === value
1523
- } else {
1524
- return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
1525
- }
1526
- })
1527
- })
1528
- }
1529
-
1530
- const total = items.length
1531
-
1532
- // Apply sorting
1533
- if (sortBy && sortBy.length > 0) {
1534
- items = items.sort((a, b) => {
1535
- const key = sortBy[0].key as keyof User
1536
- const order = sortBy[0].order === 'asc' ? 1 : -1
1537
-
1538
- return String(a[key]) > String(b[key]) ? order : -order
1539
- })
1540
- }
1541
-
1542
- // Apply pagination
1543
- if (itemsPerPage > 0) {
1544
- items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
1545
- }
1546
-
1547
- resolve({ items, total })
1548
- state.value = StateEnum.RESOLVED
1549
- })
1550
- })
1551
- }
1552
-
1553
- // Update the displayed data
1554
- users.value = filteredData
1555
- totalUsers.value = filteredData.length
1556
-
1557
- state.value = StateEnum.RESOLVED
1558
- }
1559
- // Initialize data
1560
- fetchData()
1561
- </script>
1562
- `,
1496
+ <script setup lang="ts">
1497
+ import { ref } from 'vue'
1498
+ import { SyServerTable } from '@cnamts/synapse'
1499
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
1500
+ import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
1501
+
1502
+ interface User {
1503
+ name: string
1504
+ department: string
1505
+ status: string
1506
+ }
1507
+
1508
+ interface DataObj {
1509
+ items: User[]
1510
+ total: number
1511
+ }
1512
+
1513
+ const totalFilteredUsers = ref(0)
1514
+ const filteredUsers = ref<User[]>([])
1515
+ const state = ref(StateEnum.IDLE)
1516
+
1517
+ const options = ref<DataOptions>({
1518
+ itemsPerPage: 5,
1519
+ page: 1,
1520
+ filters: [],
1521
+ })
1522
+
1523
+ const headers = [
1524
+ {
1525
+ title: 'Nom',
1526
+ key: 'name',
1527
+ filterable: true,
1528
+ filterType: 'text'
1529
+ },
1530
+ {
1531
+ title: 'Département',
1532
+ key: 'department',
1533
+ filterable: true,
1534
+ filterType: 'select',
1535
+ multiple: true,
1536
+ chips: true,
1537
+ hideMessages: true,
1538
+ filterOptions: [
1539
+ { text: 'RH', value: 'RH' },
1540
+ { text: 'IT', value: 'IT' },
1541
+ { text: 'Finance', value: 'Finance' },
1542
+ { text: 'Marketing', value: 'Marketing' },
1543
+ ]
1544
+ },
1545
+ {
1546
+ title: 'Statut',
1547
+ key: 'status',
1548
+ filterable: true,
1549
+ filterType: 'select',
1550
+ multiple: true,
1551
+ chips: true,
1552
+ hideMessages: true,
1553
+ filterOptions: [
1554
+ { text: 'Actif', value: 'Actif' },
1555
+ { text: 'En congé', value: 'En congé' },
1556
+ { text: 'Inactif', value: 'Inactif' },
1557
+ ]
1558
+ }
1559
+ ]
1560
+
1561
+ const fetchData = async (): Promise<void> => {
1562
+ const { items, total } = await getDataFromApi(options.value)
1563
+ filteredUsers.value = items
1564
+ totalFilteredUsers.value = total
1565
+ }
1566
+
1567
+ const wait = async (ms: number) => {
1568
+ return new Promise(resolve => setTimeout(resolve, ms))
1569
+ }
1570
+
1571
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
1572
+ state.value = StateEnum.PENDING
1573
+ await wait(1000)
1574
+
1575
+ return new Promise((resolve) => {
1576
+ // Get all users
1577
+ let items: User[] = getUsers()
1578
+
1579
+ // Apply filters on server side
1580
+ if (filters && filters.length > 0) {
1581
+ filters.forEach((filter: FilterOption) => {
1582
+ const { key, value, type } = filter
1583
+
1584
+ items = items.filter(item => {
1585
+ const itemValue = item[key as keyof User]
1586
+
1587
+ if (type === 'select') {
1588
+ return itemValue === value
1589
+ } else {
1590
+ return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
1591
+ }
1592
+ })
1593
+ })
1594
+ }
1595
+
1596
+ const total = items.length
1597
+
1598
+ // Apply sorting
1599
+ if (sortBy && sortBy.length > 0) {
1600
+ items = items.sort((a, b) => {
1601
+ const key = sortBy[0].key as keyof User
1602
+ const order = sortBy[0].order === 'asc' ? 1 : -1
1603
+
1604
+ return String(a[key]) > String(b[key]) ? order : -order
1605
+ })
1606
+ }
1607
+
1608
+ // Apply pagination
1609
+ if (itemsPerPage > 0) {
1610
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
1611
+ }
1612
+
1613
+ resolve({ items, total })
1614
+ state.value = StateEnum.RESOLVED
1615
+ })
1616
+ }
1617
+
1618
+ const getUsers = (): User[] => {
1619
+ return [
1620
+ { name: 'Jean Dupont', department: 'RH', status: 'Actif' },
1621
+ { name: 'Marie Martin', department: 'IT', status: 'En congé' },
1622
+ { name: 'Pierre Durand', department: 'Finance', status: 'Actif' },
1623
+ { name: 'Sophie Petit', department: 'Marketing', status: 'Actif' },
1624
+ { name: 'Thomas Leroy', department: 'IT', status: 'Inactif' },
1625
+ { name: 'Julie Bernard', department: 'RH', status: 'Actif' },
1626
+ { name: 'Nicolas Moreau', department: 'Finance', status: 'En congé' },
1627
+ { name: 'Camille Dubois', department: 'Marketing', status: 'Inactif' },
1628
+ { name: 'Alexandre Lefebvre', department: 'IT', status: 'Actif' },
1629
+ { name: 'Émilie Girard', department: 'RH', status: 'En congé' },
1630
+ { name: 'Lucas Roux', department: 'Finance', status: 'Actif' },
1631
+ { name: 'Chloé Lambert', department: 'Marketing', status: 'Actif' },
1632
+ { name: 'Maxime Simon', department: 'IT', status: 'Inactif' },
1633
+ { name: 'Laura Fournier', department: 'RH', status: 'Actif' },
1634
+ { name: 'Antoine Mercier', department: 'Finance', status: 'En congé' },
1635
+ ]
1636
+ }
1637
+
1638
+ // Initialize data
1639
+ fetchData()
1640
+ </script>
1641
+ `,
1563
1642
  },
1564
1643
  ],
1565
1644
  },
1566
1645
  args: {
1567
- serverItemsLength: 0,
1568
- showFilters: true,
1569
- headers: [
1646
+ 'headers': [
1570
1647
  {
1571
1648
  title: 'Nom',
1572
1649
  key: 'name',
@@ -1574,81 +1651,362 @@ export const ServerFilterByDate: Story = {
1574
1651
  filterType: 'text',
1575
1652
  },
1576
1653
  {
1577
- title: 'Date d\'embauche',
1578
- key: 'hireDate',
1654
+ title: 'Département',
1655
+ key: 'department',
1579
1656
  filterable: true,
1580
- filterType: 'date',
1581
- dateFormat: 'DD/MM/YYYY',
1657
+ filterType: 'select',
1658
+ multiple: true,
1659
+ chips: true,
1660
+ hideMessages: true,
1661
+ filterOptions: [
1662
+ { text: 'RH', value: 'RH' },
1663
+ { text: 'IT', value: 'IT' },
1664
+ { text: 'Finance', value: 'Finance' },
1665
+ { text: 'Marketing', value: 'Marketing' },
1666
+ ],
1582
1667
  },
1583
1668
  {
1584
- title: 'Période de congés',
1585
- key: 'vacationPeriod',
1669
+ title: 'Statut',
1670
+ key: 'status',
1586
1671
  filterable: true,
1587
- filterType: 'period',
1588
- dateFormat: 'DD/MM/YYYY',
1672
+ filterType: 'select',
1673
+ multiple: true,
1674
+ chips: true,
1675
+ hideMessages: true,
1676
+ filterOptions: [
1677
+ { text: 'Actif', value: 'Actif' },
1678
+ { text: 'En congé', value: 'En congé' },
1679
+ { text: 'Inactif', value: 'Inactif' },
1680
+ ],
1589
1681
  },
1590
1682
  ],
1591
- caption: '',
1592
- suffix: 'server-filter-date',
1593
- density: 'default',
1594
- striped: false,
1683
+ 'caption': '',
1684
+ 'options': {
1685
+ itemsPerPage: 5,
1686
+ page: 1,
1687
+ filters: [],
1688
+ },
1689
+ 'serverItemsLength': 15,
1690
+ 'showFilters': true,
1691
+ 'suffix': 'server-filter-select',
1692
+ 'density': 'default',
1693
+ 'striped': false,
1694
+ 'onUpdate:options': fn(),
1595
1695
  },
1596
1696
  render(args) {
1597
1697
  return {
1598
1698
  components: { SyServerTable },
1599
1699
  setup() {
1600
- // Original data that never changes
1601
- const originalUsers = [
1602
- {
1603
- name: 'Jean-Pierre Dubois',
1604
- hireDate: dayjs('2025-05-15').format('DD/MM/YYYY'),
1605
- vacationPeriod: {
1606
- from: dayjs('2025-07-01').format('DD/MM/YYYY'),
1607
- to: dayjs('2025-07-15').format('DD/MM/YYYY'),
1608
- },
1609
- },
1610
- {
1611
- name: 'Marie-Claire Lefèvre',
1612
- hireDate: dayjs('2025-03-10').format('DD/MM/YYYY'),
1613
- vacationPeriod: {
1614
- from: dayjs('2025-08-01').format('DD/MM/YYYY'),
1615
- to: dayjs('2025-08-20').format('DD/MM/YYYY'),
1616
- },
1617
- },
1618
- {
1619
- name: 'François Moreau',
1620
- hireDate: dayjs('2025-11-22').format('DD/MM/YYYY'),
1621
- vacationPeriod: {
1622
- from: dayjs('2025-06-15').format('DD/MM/YYYY'),
1623
- to: dayjs('2025-07-05').format('DD/MM/YYYY'),
1624
- },
1625
- },
1626
- {
1627
- name: 'Céline Rousseau',
1628
- hireDate: dayjs('2025-01-08').format('DD/MM/YYYY'),
1629
- vacationPeriod: {
1630
- from: dayjs('2025-12-20').format('DD/MM/YYYY'),
1631
- to: dayjs('2026-01-05').format('DD/MM/YYYY'),
1632
- },
1633
- },
1634
- {
1635
- name: 'Thierry Bertrand',
1636
- hireDate: dayjs('2025-07-30').format('DD/MM/YYYY'),
1637
- vacationPeriod: {
1638
- from: dayjs('2025-09-10').format('DD/MM/YYYY'),
1639
- to: dayjs('2025-09-25').format('DD/MM/YYYY'),
1640
- },
1641
- },
1642
- ]
1700
+ const options = ref({ ...args.options })
1643
1701
 
1644
- const totalUsers = ref(originalUsers.length)
1645
- const users = ref([...originalUsers])
1646
- const options = ref({
1647
- itemsPerPage: 5,
1648
- page: 1,
1649
- filters: [],
1650
- })
1651
- const state = ref(StateEnum.IDLE)
1702
+ watch(options, (newVal) => {
1703
+ if (args.options) {
1704
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
1705
+ }
1706
+ }, { deep: true })
1707
+
1708
+ const totalFilteredUsers = ref(0)
1709
+ const filteredUsers = ref<Record<string, unknown>[]>([])
1710
+ const state = ref(StateEnum.IDLE)
1711
+
1712
+ const fetchData = async (): Promise<void> => {
1713
+ state.value = StateEnum.PENDING
1714
+
1715
+ // Simulate API call
1716
+ await new Promise(resolve => setTimeout(resolve, 1000))
1717
+
1718
+ // Get all users
1719
+ let items = [
1720
+ { name: 'Jean Dupont', department: 'RH', status: 'Actif' },
1721
+ { name: 'Marie Martin', department: 'IT', status: 'En congé' },
1722
+ { name: 'Pierre Durand', department: 'Finance', status: 'Actif' },
1723
+ { name: 'Sophie Petit', department: 'Marketing', status: 'Actif' },
1724
+ { name: 'Thomas Leroy', department: 'IT', status: 'Inactif' },
1725
+ { name: 'Julie Bernard', department: 'RH', status: 'Actif' },
1726
+ { name: 'Nicolas Moreau', department: 'Finance', status: 'En congé' },
1727
+ { name: 'Camille Dubois', department: 'Marketing', status: 'Inactif' },
1728
+ { name: 'Alexandre Lefebvre', department: 'IT', status: 'Actif' },
1729
+ { name: 'Émilie Girard', department: 'RH', status: 'En congé' },
1730
+ { name: 'Lucas Roux', department: 'Finance', status: 'Actif' },
1731
+ { name: 'Chloé Lambert', department: 'Marketing', status: 'Actif' },
1732
+ { name: 'Maxime Simon', department: 'IT', status: 'Inactif' },
1733
+ { name: 'Laura Fournier', department: 'RH', status: 'Actif' },
1734
+ { name: 'Antoine Mercier', department: 'Finance', status: 'En congé' },
1735
+ ]
1736
+
1737
+ // Apply filters on server side
1738
+ if (options.value?.filters && options.value.filters.length > 0) {
1739
+ options.value.filters.forEach((filter) => {
1740
+ const { key, value, type } = filter
1741
+
1742
+ items = items.filter((item) => {
1743
+ const itemValue = item[key]
1744
+
1745
+ if (type === 'select') {
1746
+ if (Array.isArray(value)) {
1747
+ // Empty array means no filter applied
1748
+ if (value.length === 0) return true
1749
+ // Check if item value is in the selected values
1750
+ return value.includes(itemValue)
1751
+ }
1752
+ else {
1753
+ return itemValue === value
1754
+ }
1755
+ }
1756
+ else {
1757
+ return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
1758
+ }
1759
+ })
1760
+ })
1761
+ }
1762
+
1763
+ const total = items.length
1764
+
1765
+ // Apply pagination
1766
+ const { page = 1, itemsPerPage = 10 } = options.value || {}
1767
+ if (itemsPerPage > 0) {
1768
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
1769
+ }
1770
+
1771
+ filteredUsers.value = items as Record<string, unknown>[]
1772
+ totalFilteredUsers.value = total
1773
+ state.value = StateEnum.RESOLVED
1774
+ }
1775
+
1776
+ // Initialize data
1777
+ fetchData()
1778
+
1779
+ return {
1780
+ args,
1781
+ filteredUsers,
1782
+ totalFilteredUsers,
1783
+ options,
1784
+ state,
1785
+ fetchData,
1786
+ StateEnum,
1787
+ }
1788
+ },
1789
+ template: `
1790
+ <div>
1791
+ <SyServerTable
1792
+ v-bind="args"
1793
+ v-model:options="options"
1794
+ :items="filteredUsers"
1795
+ :server-items-length="totalFilteredUsers"
1796
+ :loading="state === StateEnum.PENDING"
1797
+ @update:options="fetchData"
1798
+ />
1799
+ </div>
1800
+ `,
1801
+ }
1802
+ },
1803
+ }
1804
+
1805
+ export const ServerFilterByExacteDate: Story = {
1806
+ parameters: {
1807
+ sourceCode: [
1808
+ {
1809
+ name: 'Template',
1810
+ code: `
1811
+ <template>
1812
+ <SyServerTable
1813
+ v-model:options="options"
1814
+ :items="filteredUsers"
1815
+ :headers="headers"
1816
+ :server-items-length="totalFilteredUsers"
1817
+ :loading="state === StateEnum.PENDING"
1818
+ suffix="server-filter-date"
1819
+ :show-filters="true"
1820
+ @update:options="fetchData"
1821
+ />
1822
+ </template>
1823
+ `,
1824
+ },
1825
+ {
1826
+ name: 'Script',
1827
+ code: `
1828
+ <script setup lang="ts">
1829
+ import { ref } from 'vue'
1830
+ import { SyServerTable } from '@cnamts/synapse'
1831
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
1832
+ import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
1833
+
1834
+ interface User {
1835
+ name: string
1836
+ hireDate: string
1837
+ }
1838
+
1839
+ interface DataObj {
1840
+ items: User[]
1841
+ total: number
1842
+ }
1843
+
1844
+ const totalFilteredUsers = ref(0)
1845
+ const filteredUsers = ref<User[]>([])
1846
+ const state = ref(StateEnum.IDLE)
1847
+
1848
+ const options = ref<DataOptions>({
1849
+ itemsPerPage: 5,
1850
+ page: 1,
1851
+ filters: [],
1852
+ })
1853
+
1854
+ const headers = [
1855
+ {
1856
+ title: 'Nom',
1857
+ key: 'name',
1858
+ filterable: true,
1859
+ filterType: 'text'
1860
+ },
1861
+ {
1862
+ title: 'Date d'embauche',
1863
+ key: 'hireDate',
1864
+ filterable: true,
1865
+ filterType: 'date',
1866
+ dateFormat: 'DD/MM/YYYY'
1867
+ },
1868
+ ]
1869
+
1870
+ const fetchData = async (): Promise<void> => {
1871
+ const { items, total } = await getDataFromApi(options.value)
1872
+ filteredUsers.value = items
1873
+ totalFilteredUsers.value = total
1874
+ }
1875
+
1876
+ const wait = async (ms: number) => {
1877
+ return new Promise(resolve => setTimeout(resolve, ms))
1878
+ }
1879
+
1880
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
1881
+ state.value = StateEnum.PENDING
1882
+ await wait(1000)
1883
+
1884
+ return new Promise((resolve) => {
1885
+ // Get all users
1886
+ let items: User[] = getUsers()
1887
+
1888
+ // Apply filters on server side
1889
+ if (filters && filters.length > 0) {
1890
+ filters.forEach((filter: FilterOption) => {
1891
+ const { key, value, type } = filter
1892
+
1893
+ items = items.filter(item => {
1894
+ const itemValue = item[key as keyof User]
1895
+
1896
+ if (type === 'date') {
1897
+ // Simple date comparison for demo purposes
1898
+ return itemValue === value
1899
+ } else {
1900
+ return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
1901
+ }
1902
+ })
1903
+ })
1904
+ }
1905
+
1906
+ const total = items.length
1907
+
1908
+ // Apply sorting
1909
+ if (sortBy && sortBy.length > 0) {
1910
+ items = items.sort((a, b) => {
1911
+ const key = sortBy[0].key as keyof User
1912
+ const order = sortBy[0].order === 'asc' ? 1 : -1
1913
+
1914
+ return String(a[key]) > String(b[key]) ? order : -order
1915
+ })
1916
+ }
1917
+
1918
+ // Apply pagination
1919
+ if (itemsPerPage > 0) {
1920
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
1921
+ }
1922
+
1923
+ resolve({ items, total })
1924
+ state.value = StateEnum.RESOLVED
1925
+ })
1926
+ })
1927
+ }
1928
+
1929
+ // Update the displayed data
1930
+ users.value = filteredData
1931
+ totalUsers.value = filteredData.length
1932
+
1933
+ state.value = StateEnum.RESOLVED
1934
+ }
1935
+ // Initialize data
1936
+ fetchData()
1937
+ </script>
1938
+ `,
1939
+ },
1940
+ ],
1941
+ },
1942
+ args: {
1943
+ 'serverItemsLength': 5,
1944
+ 'showFilters': true,
1945
+ 'headers': [
1946
+ {
1947
+ title: 'Nom',
1948
+ key: 'name',
1949
+ filterable: true,
1950
+ filterType: 'text',
1951
+ },
1952
+ {
1953
+ title: 'Date d\'embauche',
1954
+ key: 'hireDate',
1955
+ filterable: true,
1956
+ filterType: 'date',
1957
+ dateFormat: 'DD/MM/YYYY',
1958
+ },
1959
+ ],
1960
+ 'options': {
1961
+ itemsPerPage: 5,
1962
+ page: 1,
1963
+ filters: [],
1964
+ },
1965
+ 'caption': '',
1966
+ 'suffix': 'server-filter-date',
1967
+ 'density': 'default',
1968
+ 'striped': false,
1969
+ 'onUpdate:options': fn(),
1970
+ },
1971
+ render(args) {
1972
+ return {
1973
+ components: { SyServerTable },
1974
+ setup() {
1975
+ // Original data that never changes
1976
+ const originalUsers = [
1977
+ {
1978
+ name: 'Jean-Pierre Dubois',
1979
+ hireDate: dayjs('2025-05-15').format('DD/MM/YYYY'),
1980
+ },
1981
+ {
1982
+ name: 'Marie-Claire Lefèvre',
1983
+ hireDate: dayjs('2025-03-10').format('DD/MM/YYYY'),
1984
+ },
1985
+ {
1986
+ name: 'François Moreau',
1987
+ hireDate: dayjs('2025-11-22').format('DD/MM/YYYY'),
1988
+ },
1989
+ {
1990
+ name: 'Céline Rousseau',
1991
+ hireDate: dayjs('2025-01-08').format('DD/MM/YYYY'),
1992
+ },
1993
+ {
1994
+ name: 'Thierry Bertrand',
1995
+ hireDate: dayjs('2025-07-30').format('DD/MM/YYYY'),
1996
+ },
1997
+ ]
1998
+
1999
+ const options = ref({ ...args.options })
2000
+
2001
+ watch(options, (newVal) => {
2002
+ if (args.options) {
2003
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
2004
+ }
2005
+ }, { deep: true })
2006
+
2007
+ const totalUsers = ref(originalUsers.length)
2008
+ const users = ref([...originalUsers])
2009
+ const state = ref(StateEnum.IDLE)
1652
2010
 
1653
2011
  const fetchData = async () => {
1654
2012
  state.value = StateEnum.PENDING
@@ -1673,20 +2031,20 @@ export const ServerFilterByDate: Story = {
1673
2031
  return itemValue === value
1674
2032
  }
1675
2033
  else if (type === 'period') {
1676
- // Handle period filter type
1677
- const period = itemValue as { from: string, to: string }
1678
- const filterPeriod = value as { from: string, to: string }
1679
-
1680
- // Simple period comparison for demo purposes
1681
- if (filterPeriod.from && !filterPeriod.to) {
1682
- return period.from === filterPeriod.from
1683
- }
1684
- else if (!filterPeriod.from && filterPeriod.to) {
1685
- return period.to === filterPeriod.to
1686
- }
1687
- else if (filterPeriod.from && filterPeriod.to) {
1688
- return period.from === filterPeriod.from && period.to === filterPeriod.to
2034
+ const filter = value as { from: string, to: string }
2035
+ const start = new Date(filter.from)
2036
+ const end = new Date(filter.to)
2037
+ const itemDate = new Date(itemValue)
2038
+
2039
+ if (itemDate) {
2040
+ if (end && itemDate < end) {
2041
+ return false
2042
+ }
2043
+ if (start && itemDate > start) {
2044
+ return false
2045
+ }
1689
2046
  }
2047
+
1690
2048
  return true
1691
2049
  }
1692
2050
  else {
@@ -1703,6 +2061,9 @@ export const ServerFilterByDate: Story = {
1703
2061
  state.value = StateEnum.RESOLVED
1704
2062
  }
1705
2063
 
2064
+ // Initialize data
2065
+ fetchData()
2066
+
1706
2067
  return {
1707
2068
  args,
1708
2069
  users,
@@ -1716,17 +2077,11 @@ export const ServerFilterByDate: Story = {
1716
2077
  template: `
1717
2078
  <div>
1718
2079
  <SyServerTable
2080
+ v-bind="args"
1719
2081
  v-model:options="options"
1720
2082
  :items="users"
1721
- :headers="args.headers"
1722
- :caption="args.caption"
1723
2083
  :server-items-length="totalUsers"
1724
2084
  :loading="state === StateEnum.PENDING"
1725
- :resizable-columns="args.resizableColumns"
1726
- :show-filters="true"
1727
- :suffix="args.suffix"
1728
- :density="args.density"
1729
- :striped="args.striped"
1730
2085
  @update:options="fetchData"
1731
2086
  />
1732
2087
  </div>
@@ -1735,71 +2090,376 @@ export const ServerFilterByDate: Story = {
1735
2090
  },
1736
2091
  }
1737
2092
 
1738
- export const CustomFilterSlot: Story = {
2093
+ export const ServerFilterByPeriod: Story = {
1739
2094
  parameters: {
1740
2095
  sourceCode: [
1741
2096
  {
1742
2097
  name: 'Template',
1743
2098
  code: `
1744
- <template>
1745
- <SyServerTable
1746
- v-model:options="options"
1747
- :headers="headers"
1748
- :items="items"
1749
- :server-items-length="serverItemsLength"
1750
- :loading="loading"
1751
- show-filters
1752
- suffix="server-custom-filter-slot"
1753
- @update:options="fetchData"
1754
- >
1755
- <template #filter.custom="{ header, value, updateFilter }">
1756
- <div class="custom-filter-container">
1757
- <div class="custom-filter-info mb-2">
1758
- Filtre personnalisé :
1759
- </div>
1760
- <v-select
1761
- v-model="customFilterValue"
1762
- :items="statusOptions"
1763
- label="Statut"
1764
- variant="outlined"
1765
- density="compact"
1766
- color="primary"
1767
- bg-color="white"
1768
- @update:model-value="(val) => {
1769
- // Utiliser la fonction updateFilter fournie par le slot
1770
- updateFilter(val)
1771
- }"
1772
- />
1773
- </div>
1774
- </template>
1775
- </SyServerTable>
1776
- </template>
1777
- `,
2099
+ <template>
2100
+ <SyServerTable
2101
+ v-model:options="options"
2102
+ :items="filteredUsers"
2103
+ :headers="headers"
2104
+ :server-items-length="totalFilteredUsers"
2105
+ :loading="state === StateEnum.PENDING"
2106
+ suffix="server-filter-date"
2107
+ :show-filters="true"
2108
+ @update:options="fetchData"
2109
+ />
2110
+ </template>
2111
+ `,
1778
2112
  },
1779
2113
  {
1780
2114
  name: 'Script',
1781
2115
  code: `
1782
- <script setup lang="ts">
1783
- import { ref } from 'vue'
1784
- import { SyServerTable } from '@cnamts/synapse'
1785
- import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
1786
- import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
1787
-
1788
- const options = ref<Partial<DataOptions>>({
1789
- itemsPerPage: 4,
1790
- filters: []
1791
- })
1792
-
1793
- const customFilterValue = ref('')
1794
- const statusOptions = ['Actif', 'Inactif', 'En attente']
1795
- const loading = ref(false)
1796
- const serverItemsLength = ref(6)
2116
+ <script setup lang="ts">
2117
+ import { ref } from 'vue'
2118
+ import { SyServerTable } from '@cnamts/synapse'
2119
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
2120
+ import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
2121
+
2122
+ interface User {
2123
+ name: string
2124
+ hireDate: string
2125
+ }
2126
+
2127
+ interface DataObj {
2128
+ items: User[]
2129
+ total: number
2130
+ }
2131
+
2132
+ const totalFilteredUsers = ref(0)
2133
+ const filteredUsers = ref<User[]>([])
2134
+ const state = ref(StateEnum.IDLE)
2135
+
2136
+ const options = ref<DataOptions>({
2137
+ itemsPerPage: 5,
2138
+ page: 1,
2139
+ filters: [],
2140
+ })
2141
+
2142
+ const headers = [
2143
+ {
2144
+ title: 'Nom',
2145
+ key: 'name',
2146
+ filterable: true,
2147
+ filterType: 'text'
2148
+ },
2149
+ {
2150
+ title: 'Date d'embauche',
2151
+ key: 'hireDate',
2152
+ filterable: true,
2153
+ filterType: 'periode',
2154
+ dateFormat: 'DD/MM/YYYY'
2155
+ },
2156
+ ]
2157
+
2158
+ const fetchData = async (): Promise<void> => {
2159
+ const { items, total } = await getDataFromApi(options.value)
2160
+ filteredUsers.value = items
2161
+ totalFilteredUsers.value = total
2162
+ }
2163
+
2164
+ const wait = async (ms: number) => {
2165
+ return new Promise(resolve => setTimeout(resolve, ms))
2166
+ }
2167
+
2168
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
2169
+ state.value = StateEnum.PENDING
2170
+ await wait(1000)
2171
+
2172
+ return new Promise((resolve) => {
2173
+ // Get all users
2174
+ let items: User[] = getUsers()
2175
+
2176
+ // Apply filters on server side
2177
+ if (filters && filters.length > 0) {
2178
+ filters.forEach((filter: FilterOption) => {
2179
+ const { key, value, type } = filter
2180
+
2181
+ items = items.filter(item => {
2182
+ const itemValue = item[key as keyof User]
1797
2183
 
1798
- const headers = [
1799
- {
1800
- title: 'Nom',
1801
- key: 'lastname',
1802
- filterable: true,
2184
+ if (type === 'period') {
2185
+ function formatDate(date: string): Date | null {
2186
+ if (!date) return null
2187
+ const parsedDate = dayjs(date, 'DD/MM/YYYY')
2188
+ return parsedDate.isValid() ? parsedDate.toDate() : null
2189
+ }
2190
+ const filter = value as { from: string, to: string }
2191
+ const start = formatDate(filter.from)
2192
+ const end = formatDate(filter.to)
2193
+ const itemDate = formatDate(itemValue)
2194
+
2195
+ if (itemDate) {
2196
+ if (end && itemDate > end) {
2197
+ return false
2198
+ }
2199
+ if (start && itemDate < start) {
2200
+ return false
2201
+ }
2202
+ }
2203
+ return true
2204
+ } else {
2205
+ return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
2206
+ }
2207
+ })
2208
+ })
2209
+ }
2210
+
2211
+ const total = items.length
2212
+
2213
+ // Apply sorting
2214
+ if (sortBy && sortBy.length > 0) {
2215
+ items = items.sort((a, b) => {
2216
+ const key = sortBy[0].key as keyof User
2217
+ const order = sortBy[0].order === 'asc' ? 1 : -1
2218
+
2219
+ return String(a[key]) > String(b[key]) ? order : -order
2220
+ })
2221
+ }
2222
+
2223
+ // Apply pagination
2224
+ if (itemsPerPage > 0) {
2225
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
2226
+ }
2227
+
2228
+ resolve({ items, total })
2229
+ state.value = StateEnum.RESOLVED
2230
+ })
2231
+ })
2232
+ }
2233
+
2234
+ // Update the displayed data
2235
+ users.value = filteredData
2236
+ totalUsers.value = filteredData.length
2237
+
2238
+ state.value = StateEnum.RESOLVED
2239
+ }
2240
+ // Initialize data
2241
+ fetchData()
2242
+ </script>
2243
+ `,
2244
+ },
2245
+ ],
2246
+ },
2247
+ args: {
2248
+ 'serverItemsLength': 5,
2249
+ 'showFilters': true,
2250
+ 'headers': [
2251
+ {
2252
+ title: 'Nom',
2253
+ key: 'name',
2254
+ filterable: true,
2255
+ filterType: 'text',
2256
+ },
2257
+ {
2258
+ title: 'Date d\'embauche',
2259
+ key: 'hireDate',
2260
+ filterable: true,
2261
+ filterType: 'period',
2262
+ dateFormat: 'DD/MM/YYYY',
2263
+ },
2264
+ ],
2265
+ 'options': {
2266
+ itemsPerPage: 5,
2267
+ page: 1,
2268
+ filters: [],
2269
+ },
2270
+ 'caption': '',
2271
+ 'suffix': 'server-filter-date',
2272
+ 'density': 'default',
2273
+ 'striped': false,
2274
+ 'onUpdate:options': fn(),
2275
+ },
2276
+ render(args) {
2277
+ return {
2278
+ components: { SyServerTable },
2279
+ setup() {
2280
+ // Original data that never changes
2281
+ const originalUsers = [
2282
+ {
2283
+ name: 'Jean-Pierre Dubois',
2284
+ hireDate: dayjs('2025-05-15').format('DD/MM/YYYY'),
2285
+ },
2286
+ {
2287
+ name: 'Marie-Claire Lefèvre',
2288
+ hireDate: dayjs('2025-03-10').format('DD/MM/YYYY'),
2289
+ },
2290
+ {
2291
+ name: 'François Moreau',
2292
+ hireDate: dayjs('2025-11-22').format('DD/MM/YYYY'),
2293
+ },
2294
+ {
2295
+ name: 'Céline Rousseau',
2296
+ hireDate: dayjs('2025-01-08').format('DD/MM/YYYY'),
2297
+ },
2298
+ {
2299
+ name: 'Thierry Bertrand',
2300
+ hireDate: dayjs('2025-07-30').format('DD/MM/YYYY'),
2301
+ },
2302
+ ]
2303
+
2304
+ const options = ref({ ...args.options })
2305
+
2306
+ watch(options, (newVal) => {
2307
+ if (args.options) {
2308
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
2309
+ }
2310
+ }, { deep: true })
2311
+
2312
+ const totalUsers = ref(originalUsers.length)
2313
+ const users = ref([...originalUsers])
2314
+ const state = ref(StateEnum.IDLE)
2315
+
2316
+ const fetchData = async () => {
2317
+ state.value = StateEnum.PENDING
2318
+
2319
+ // Simulate API delay
2320
+ await new Promise(resolve => setTimeout(resolve, 1000))
2321
+
2322
+ // Start with original data
2323
+ let filteredData = [...originalUsers]
2324
+
2325
+ // Apply filters if any
2326
+ if (options.value.filters && options.value.filters.length > 0) {
2327
+ filteredData = filteredData.filter((user) => {
2328
+ return options.value.filters!.every((filter) => {
2329
+ const { key, value, type } = filter
2330
+ const itemValue = user[key as keyof typeof user]
2331
+
2332
+ if (!value) return true
2333
+
2334
+ else if (type === 'period') {
2335
+ function formatDate(date: string): Date | null {
2336
+ if (!date) return null
2337
+ const parsedDate = dayjs(date, 'DD/MM/YYYY')
2338
+ return parsedDate.isValid() ? parsedDate.toDate() : null
2339
+ }
2340
+ const filter = value as { from: string, to: string }
2341
+ const start = formatDate(filter.from)
2342
+ const end = formatDate(filter.to)
2343
+ const itemDate = formatDate(itemValue)
2344
+
2345
+ if (itemDate) {
2346
+ if (end && itemDate > end) {
2347
+ return false
2348
+ }
2349
+ if (start && itemDate < start) {
2350
+ return false
2351
+ }
2352
+ }
2353
+ return true
2354
+ }
2355
+ else {
2356
+ return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
2357
+ }
2358
+ })
2359
+ })
2360
+ }
2361
+
2362
+ // Update the displayed data
2363
+ users.value = filteredData
2364
+ totalUsers.value = filteredData.length
2365
+
2366
+ state.value = StateEnum.RESOLVED
2367
+ }
2368
+
2369
+ // Initialize data
2370
+ fetchData()
2371
+
2372
+ return {
2373
+ args,
2374
+ users,
2375
+ totalUsers,
2376
+ options,
2377
+ state,
2378
+ fetchData,
2379
+ StateEnum,
2380
+ }
2381
+ },
2382
+ template: `
2383
+ <div>
2384
+ <SyServerTable
2385
+ v-bind="args"
2386
+ v-model:options="options"
2387
+ :items="users"
2388
+ :server-items-length="totalUsers"
2389
+ :loading="state === StateEnum.PENDING"
2390
+ @update:options="fetchData"
2391
+ />
2392
+ </div>
2393
+ `,
2394
+ }
2395
+ },
2396
+ }
2397
+
2398
+ export const CustomFilterSlot: Story = {
2399
+ parameters: {
2400
+ sourceCode: [
2401
+ {
2402
+ name: 'Template',
2403
+ code: `
2404
+ <template>
2405
+ <SyServerTable
2406
+ v-model:options="options"
2407
+ :headers="headers"
2408
+ :items="items"
2409
+ :server-items-length="serverItemsLength"
2410
+ :loading="loading"
2411
+ show-filters
2412
+ suffix="server-custom-filter-slot"
2413
+ @update:options="fetchData"
2414
+ >
2415
+ <template #filter.custom="{ header, value, updateFilter }">
2416
+ <div class="custom-filter-container">
2417
+ <div class="custom-filter-info mb-2">
2418
+ Filtre personnalisé :
2419
+ </div>
2420
+ <v-select
2421
+ v-model="customFilterValue"
2422
+ :items="statusOptions"
2423
+ label="Statut"
2424
+ variant="outlined"
2425
+ density="compact"
2426
+ color="primary"
2427
+ bg-color="white"
2428
+ @update:model-value="(val) => {
2429
+ // Utiliser la fonction updateFilter fournie par le slot
2430
+ updateFilter(val)
2431
+ }"
2432
+ />
2433
+ </div>
2434
+ </template>
2435
+ </SyServerTable>
2436
+ </template>
2437
+ `,
2438
+ },
2439
+ {
2440
+ name: 'Script',
2441
+ code: `
2442
+ <script setup lang="ts">
2443
+ import { ref, watch } from 'vue'
2444
+ import { SyServerTable } from '@cnamts/synapse'
2445
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
2446
+ import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
2447
+
2448
+ const options = ref<Partial<DataOptions>>({
2449
+ itemsPerPage: 4,
2450
+ filters: []
2451
+ })
2452
+
2453
+ const customFilterValue = ref('')
2454
+ const statusOptions = ['Actif', 'Inactif', 'En attente']
2455
+ const loading = ref(false)
2456
+ const serverItemsLength = ref(6)
2457
+
2458
+ const headers = [
2459
+ {
2460
+ title: 'Nom',
2461
+ key: 'lastname',
2462
+ filterable: true,
1803
2463
  filterType: 'text'
1804
2464
  },
1805
2465
  {
@@ -1916,8 +2576,8 @@ export const CustomFilterSlot: Story = {
1916
2576
  ],
1917
2577
  },
1918
2578
  args: {
1919
- serverItemsLength: 6,
1920
- headers: [
2579
+ 'serverItemsLength': 6,
2580
+ 'headers': [
1921
2581
  {
1922
2582
  title: 'Nom',
1923
2583
  key: 'lastname',
@@ -1937,7 +2597,7 @@ export const CustomFilterSlot: Story = {
1937
2597
  filterType: 'custom' as FilterType,
1938
2598
  },
1939
2599
  ],
1940
- items: [
2600
+ 'items': [
1941
2601
  {
1942
2602
  firstname: 'Virginie',
1943
2603
  lastname: 'Beauchesne',
@@ -1969,22 +2629,31 @@ export const CustomFilterSlot: Story = {
1969
2629
  status: 'En attente',
1970
2630
  },
1971
2631
  ],
1972
- caption: '',
1973
- options: {
2632
+ 'caption': '',
2633
+ 'options': {
1974
2634
  itemsPerPage: 4,
2635
+ page: 1,
1975
2636
  filters: [],
1976
2637
  },
1977
- showFilters: true,
1978
- suffix: 'server-custom-filter-slot',
1979
- density: 'default',
1980
- striped: false,
2638
+ 'showFilters': true,
2639
+ 'suffix': 'server-custom-filter-slot',
2640
+ 'density': 'default',
2641
+ 'striped': false,
2642
+ 'onUpdate:options': fn(),
1981
2643
  },
1982
2644
  render(args) {
1983
2645
  return {
1984
2646
  components: { SyServerTable },
1985
2647
  setup() {
1986
2648
  // Create reactive references
1987
- const options = ref(args.options)
2649
+ const options = ref({ ...args.options })
2650
+
2651
+ watch(options, (newVal) => {
2652
+ if (args.options) {
2653
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
2654
+ }
2655
+ }, { deep: true })
2656
+
1988
2657
  const items = ref(args.items)
1989
2658
  const customFilterValue = ref('')
1990
2659
  const statusOptions = ['Actif', 'Inactif', 'En attente']
@@ -2031,6 +2700,35 @@ export const CustomFilterSlot: Story = {
2031
2700
  loading.value = false
2032
2701
  }
2033
2702
 
2703
+ function handleFilterChange(val) {
2704
+ // Ensure options.value.filters is initialized
2705
+ if (!options.value.filters) {
2706
+ options.value.filters = []
2707
+ }
2708
+
2709
+ // Create a new filters array with proper typing
2710
+ const currentFilters = options.value.filters as import('../common/types').FilterOption[]
2711
+ const newFilters = [...currentFilters].filter(f => f.key !== 'status')
2712
+
2713
+ // Add the new filter if a value is selected
2714
+ if (val) {
2715
+ newFilters.push({
2716
+ key: 'status',
2717
+ value: val,
2718
+ type: 'select' as FilterType, // Use 'select' type for compatibility with filtering logic
2719
+ })
2720
+ }
2721
+
2722
+ // Update the options with the new filters
2723
+ options.value = {
2724
+ ...options.value,
2725
+ filters: newFilters,
2726
+ }
2727
+ }
2728
+
2729
+ // Initialize data
2730
+ fetchData()
2731
+
2034
2732
  return {
2035
2733
  args,
2036
2734
  options,
@@ -2039,22 +2737,17 @@ export const CustomFilterSlot: Story = {
2039
2737
  statusOptions,
2040
2738
  loading,
2041
2739
  serverItemsLength,
2740
+ handleFilterChange,
2042
2741
  fetchData,
2043
2742
  }
2044
2743
  },
2045
2744
  template: `
2046
2745
  <SyServerTable
2746
+ v-bind="args"
2047
2747
  v-model:options="options"
2048
- :headers="args.headers"
2049
2748
  :items="items"
2050
- :caption="args.caption"
2051
2749
  :server-items-length="serverItemsLength"
2052
2750
  :loading="loading"
2053
- :show-filters="args.showFilters"
2054
- :suffix="args.suffix"
2055
- :density="args.density"
2056
- :striped="args.striped"
2057
- :resizable-columns="args.resizableColumns"
2058
2751
  @update:options="fetchData"
2059
2752
  >
2060
2753
  <template #filter.custom="{ header, value, updateFilter }">
@@ -2071,8 +2764,10 @@ export const CustomFilterSlot: Story = {
2071
2764
  color="primary"
2072
2765
  bg-color="white"
2073
2766
  @update:model-value="(val) => {
2074
- // Utiliser la fonction updateFilter fournie par le slot
2075
- updateFilter(val)
2767
+ // Use updateFilter provided by the slot props
2768
+ updateFilter(val);
2769
+ // Also update our local state
2770
+ handleFilterChange(val);
2076
2771
  }"
2077
2772
  />
2078
2773
  </div>
@@ -2089,73 +2784,73 @@ export const CustomFilterInputs: Story = {
2089
2784
  {
2090
2785
  name: 'Template',
2091
2786
  code: `
2092
- <template>
2093
- <SyServerTable
2094
- v-model:options="options"
2095
- :items="filteredUsers"
2096
- :headers="headers"
2097
- :server-items-length="totalFilteredUsers"
2098
- :filter-input-config="filterInputConfig"
2099
- :loading="state === StateEnum.PENDING"
2100
- suffix="server-filter-text"
2101
- :show-filters="true"
2102
- @update:options="fetchData"
2103
- />
2104
- </template>
2105
- `,
2787
+ <template>
2788
+ <SyServerTable
2789
+ v-model:options="options"
2790
+ :items="filteredUsers"
2791
+ :headers="headers"
2792
+ :server-items-length="totalFilteredUsers"
2793
+ :filter-input-config="filterInputConfig"
2794
+ :loading="state === StateEnum.PENDING"
2795
+ suffix="server-filter-text"
2796
+ :show-filters="true"
2797
+ @update:options="fetchData"
2798
+ />
2799
+ </template>
2800
+ `,
2106
2801
  },
2107
2802
  {
2108
2803
  name: 'Script',
2109
2804
  code: `
2110
- <script setup lang="ts">
2111
- import { ref } from 'vue'
2112
- import { SyServerTable } from '@cnamts/synapse'
2113
- import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
2114
- import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
2115
-
2116
- interface User {
2117
- firstname: string
2118
- lastname: string
2119
- email: string
2120
- }
2121
-
2122
- interface DataObj {
2123
- items: User[]
2124
- total: number
2125
- }
2126
-
2127
- const totalFilteredUsers = ref(0)
2128
- const filteredUsers = ref<User[]>([])
2129
- const state = ref(StateEnum.IDLE)
2130
-
2131
- const options = ref<DataOptions>({
2132
- itemsPerPage: 5,
2133
- page: 1,
2134
- filters: [],
2135
- })
2136
-
2137
- const headers = [
2138
- {
2139
- title: 'Prénom',
2140
- key: 'firstname',
2141
- filterable: true,
2142
- filterType: 'text'
2143
- },
2144
- {
2145
- title: 'Nom',
2146
- key: 'lastname',
2147
- filterable: true,
2148
- filterType: 'text'
2149
- },
2150
- {
2151
- title: 'Email',
2152
- key: 'email',
2153
- filterable: true,
2154
- filterType: 'text'
2155
- }
2156
- ]
2157
-
2158
- const filterInputConfig = {
2805
+ <script setup lang="ts">
2806
+ import { ref } from 'vue'
2807
+ import { SyServerTable } from '@cnamts/synapse'
2808
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
2809
+ import type { DataOptions, FilterOption } from '@cnamts/synapse/src/components/Tables/common/types'
2810
+
2811
+ interface User {
2812
+ firstname: string
2813
+ lastname: string
2814
+ email: string
2815
+ }
2816
+
2817
+ interface DataObj {
2818
+ items: User[]
2819
+ total: number
2820
+ }
2821
+
2822
+ const totalFilteredUsers = ref(0)
2823
+ const filteredUsers = ref<User[]>([])
2824
+ const state = ref(StateEnum.IDLE)
2825
+
2826
+ const options = ref<DataOptions>({
2827
+ itemsPerPage: 5,
2828
+ page: 1,
2829
+ filters: [],
2830
+ })
2831
+
2832
+ const headers = [
2833
+ {
2834
+ title: 'Prénom',
2835
+ key: 'firstname',
2836
+ filterable: true,
2837
+ filterType: 'text'
2838
+ },
2839
+ {
2840
+ title: 'Nom',
2841
+ key: 'lastname',
2842
+ filterable: true,
2843
+ filterType: 'text'
2844
+ },
2845
+ {
2846
+ title: 'Email',
2847
+ key: 'email',
2848
+ filterable: true,
2849
+ filterType: 'text'
2850
+ }
2851
+ ]
2852
+
2853
+ const filterInputConfig = {
2159
2854
  filterInputConfig: {
2160
2855
  variant: 'outlined',
2161
2856
  density: 'comfortable',
@@ -2165,88 +2860,88 @@ export const CustomFilterInputs: Story = {
2165
2860
  },
2166
2861
  }
2167
2862
 
2168
- const fetchData = async (): Promise<void> => {
2169
- const { items, total } = await getDataFromApi(options.value)
2170
- filteredUsers.value = items
2171
- totalFilteredUsers.value = total
2172
- }
2173
-
2174
- const wait = async (ms: number) => {
2175
- return new Promise(resolve => setTimeout(resolve, ms))
2176
- }
2177
-
2178
- const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
2179
- state.value = StateEnum.PENDING
2180
- await wait(1000)
2181
-
2182
- return new Promise((resolve) => {
2183
- // Get all users
2184
- let items: User[] = getUsers()
2185
-
2186
- // Apply filters on server side
2187
- if (filters && filters.length > 0) {
2188
- filters.forEach((filter: FilterOption) => {
2189
- const { key, value } = filter
2190
-
2191
- items = items.filter(item => {
2192
- const itemValue = item[key as keyof User]
2193
- return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
2194
- })
2195
- })
2196
- }
2197
-
2198
- const total = items.length
2199
-
2200
- // Apply sorting
2201
- if (sortBy && sortBy.length > 0) {
2202
- items = items.sort((a, b) => {
2203
- const key = sortBy[0].key as keyof User
2204
- const order = sortBy[0].order === 'asc' ? 1 : -1
2205
-
2206
- return String(a[key]) > String(b[key]) ? order : -order
2207
- })
2208
- }
2209
-
2210
- // Apply pagination
2211
- if (itemsPerPage > 0) {
2212
- items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
2213
- }
2214
-
2215
- resolve({ items, total })
2216
- state.value = StateEnum.RESOLVED
2217
- })
2218
- }
2219
-
2220
- const getUsers = (): User[] => {
2221
- return [
2222
- { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
2223
- { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
2224
- { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
2225
- { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
2226
- { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
2227
- { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
2228
- { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
2229
- { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
2230
- { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
2231
- { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
2232
- { firstname: 'Martin', lastname: 'Lavoie', email: 'martin.lavoie@example.com' },
2233
- { firstname: 'Céline', lastname: 'Tremblay', email: 'celine.tremblay@example.com' },
2234
- { firstname: 'Jacques', lastname: 'Gagnon', email: 'jacques.gagnon@example.com' },
2235
- { firstname: 'Isabelle', lastname: 'Côté', email: 'isabelle.cote@example.com' },
2236
- { firstname: 'Philippe', lastname: 'Bouchard', email: 'philippe.bouchard@example.com' },
2237
- ]
2238
- }
2239
-
2240
- // Initialize data
2241
- fetchData()
2242
- </script>
2243
- `,
2863
+ const fetchData = async (): Promise<void> => {
2864
+ const { items, total } = await getDataFromApi(options.value)
2865
+ filteredUsers.value = items
2866
+ totalFilteredUsers.value = total
2867
+ }
2868
+
2869
+ const wait = async (ms: number) => {
2870
+ return new Promise(resolve => setTimeout(resolve, ms))
2871
+ }
2872
+
2873
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
2874
+ state.value = StateEnum.PENDING
2875
+ await wait(1000)
2876
+
2877
+ return new Promise((resolve) => {
2878
+ // Get all users
2879
+ let items: User[] = getUsers()
2880
+
2881
+ // Apply filters on server side
2882
+ if (filters && filters.length > 0) {
2883
+ filters.forEach((filter: FilterOption) => {
2884
+ const { key, value } = filter
2885
+
2886
+ items = items.filter(item => {
2887
+ const itemValue = item[key as keyof User]
2888
+ return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
2889
+ })
2890
+ })
2891
+ }
2892
+
2893
+ const total = items.length
2894
+
2895
+ // Apply sorting
2896
+ if (sortBy && sortBy.length > 0) {
2897
+ items = items.sort((a, b) => {
2898
+ const key = sortBy[0].key as keyof User
2899
+ const order = sortBy[0].order === 'asc' ? 1 : -1
2900
+
2901
+ return String(a[key]) > String(b[key]) ? order : -order
2902
+ })
2903
+ }
2904
+
2905
+ // Apply pagination
2906
+ if (itemsPerPage > 0) {
2907
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
2908
+ }
2909
+
2910
+ resolve({ items, total })
2911
+ state.value = StateEnum.RESOLVED
2912
+ })
2913
+ }
2914
+
2915
+ const getUsers = (): User[] => {
2916
+ return [
2917
+ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
2918
+ { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
2919
+ { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
2920
+ { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
2921
+ { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
2922
+ { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
2923
+ { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
2924
+ { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
2925
+ { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
2926
+ { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
2927
+ { firstname: 'Martin', lastname: 'Lavoie', email: 'martin.lavoie@example.com' },
2928
+ { firstname: 'Céline', lastname: 'Tremblay', email: 'celine.tremblay@example.com' },
2929
+ { firstname: 'Jacques', lastname: 'Gagnon', email: 'jacques.gagnon@example.com' },
2930
+ { firstname: 'Isabelle', lastname: 'Côté', email: 'isabelle.cote@example.com' },
2931
+ { firstname: 'Philippe', lastname: 'Bouchard', email: 'philippe.bouchard@example.com' },
2932
+ ]
2933
+ }
2934
+
2935
+ // Initialize data
2936
+ fetchData()
2937
+ </script>
2938
+ `,
2244
2939
  },
2245
2940
  ],
2246
2941
  },
2247
2942
  args: {
2248
- serverItemsLength: 15,
2249
- headers: [
2943
+ 'serverItemsLength': 15,
2944
+ 'headers': [
2250
2945
  {
2251
2946
  title: 'Prénom',
2252
2947
  key: 'firstname',
@@ -2266,29 +2961,37 @@ export const CustomFilterInputs: Story = {
2266
2961
  filterType: 'text',
2267
2962
  },
2268
2963
  ],
2269
- caption: '',
2270
- options: {
2964
+ 'caption': '',
2965
+ 'options': {
2271
2966
  itemsPerPage: 5,
2272
2967
  page: 1,
2273
2968
  filters: [],
2274
2969
  },
2275
- filterInputConfig: {
2970
+ 'filterInputConfig': {
2276
2971
  variant: 'outlined',
2277
2972
  density: 'comfortable',
2278
2973
  hideDetails: true,
2279
2974
  clearable: false,
2280
2975
  disableErrorHandling: true,
2281
2976
  },
2282
- showFilters: true,
2283
- suffix: 'server-filter-text',
2284
- density: 'default',
2285
- striped: false,
2977
+ 'showFilters': true,
2978
+ 'suffix': 'server-filter-text',
2979
+ 'density': 'default',
2980
+ 'striped': false,
2981
+ 'onUpdate:options': fn(),
2286
2982
  },
2287
2983
  render(args) {
2288
2984
  return {
2289
2985
  components: { SyServerTable },
2290
2986
  setup() {
2291
- const options = ref(args.options)
2987
+ const options = ref({ ...args.options })
2988
+
2989
+ watch(options, (newVal) => {
2990
+ if (args.options) {
2991
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
2992
+ }
2993
+ }, { deep: true })
2994
+
2292
2995
  const totalFilteredUsers = ref(0)
2293
2996
  const filteredUsers = ref<Record<string, unknown>[]>([])
2294
2997
  const state = ref(StateEnum.IDLE)
@@ -2299,8 +3002,817 @@ export const CustomFilterInputs: Story = {
2299
3002
  // Simulate API call
2300
3003
  await new Promise(resolve => setTimeout(resolve, 1000))
2301
3004
 
2302
- // Get all users
2303
- let items = [
3005
+ // Get all users
3006
+ let items = [
3007
+ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
3008
+ { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
3009
+ { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
3010
+ { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
3011
+ { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
3012
+ { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
3013
+ { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
3014
+ { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
3015
+ { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
3016
+ { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
3017
+ { firstname: 'Martin', lastname: 'Lavoie', email: 'martin.lavoie@example.com' },
3018
+ { firstname: 'Céline', lastname: 'Tremblay', email: 'celine.tremblay@example.com' },
3019
+ { firstname: 'Jacques', lastname: 'Gagnon', email: 'jacques.gagnon@example.com' },
3020
+ { firstname: 'Isabelle', lastname: 'Côté', email: 'isabelle.cote@example.com' },
3021
+ { firstname: 'Philippe', lastname: 'Bouchard', email: 'philippe.bouchard@example.com' },
3022
+ ]
3023
+
3024
+ // Apply filters on server side
3025
+ if (options.value?.filters && options.value.filters.length > 0) {
3026
+ options.value.filters.forEach((filter) => {
3027
+ const { key, value } = filter
3028
+
3029
+ items = items.filter((item) => {
3030
+ const itemValue = item[key]
3031
+ return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
3032
+ })
3033
+ })
3034
+ }
3035
+
3036
+ const total = items.length
3037
+
3038
+ // Apply pagination
3039
+ const { page = 1, itemsPerPage = 10 } = options.value || {}
3040
+ if (itemsPerPage > 0) {
3041
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
3042
+ }
3043
+
3044
+ filteredUsers.value = items as Record<string, unknown>[]
3045
+ totalFilteredUsers.value = total
3046
+ state.value = StateEnum.RESOLVED
3047
+ }
3048
+
3049
+ // Initialize data
3050
+ fetchData()
3051
+
3052
+ return {
3053
+ args,
3054
+ filteredUsers,
3055
+ totalFilteredUsers,
3056
+ options,
3057
+ state,
3058
+ fetchData,
3059
+ StateEnum,
3060
+ }
3061
+ },
3062
+ template: `
3063
+ <div>
3064
+ <SyServerTable
3065
+ v-bind="args"
3066
+ v-model:options="options"
3067
+ :items="filteredUsers"
3068
+ :server-items-length="totalFilteredUsers"
3069
+ :loading="state === StateEnum.PENDING"
3070
+ @update:options="fetchData"
3071
+ />
3072
+ </div>
3073
+ `,
3074
+ }
3075
+ },
3076
+ }
3077
+
3078
+ export const ManyServerTables: Story = {
3079
+ parameters: {
3080
+ sourceCode: [
3081
+ {
3082
+ name: 'Template',
3083
+ code: `
3084
+ <template>
3085
+ <div>
3086
+ <SyServerTable
3087
+ v-model:options="optionsTable1"
3088
+ :items="usersTable1"
3089
+ :headers="headers"
3090
+ :server-items-length="totalUsersTable1"
3091
+ :loading="stateTable1 === StateEnum.PENDING"
3092
+ suffix="table1"
3093
+ @update:options="fetchDataTable1"
3094
+ />
3095
+ <SyServerTable
3096
+ v-model:options="optionsTable2"
3097
+ :items="usersTable2"
3098
+ :headers="headers"
3099
+ :server-items-length="totalUsersTable2"
3100
+ :loading="stateTable2 === StateEnum.PENDING"
3101
+ suffix="table2"
3102
+ @update:options="fetchDataTable2"
3103
+ />
3104
+ </div>
3105
+ </template>
3106
+ `,
3107
+ },
3108
+ {
3109
+ name: 'Script',
3110
+ code: `
3111
+ <script setup lang="ts">
3112
+ import { ref } from 'vue'
3113
+ import { SyServerTable } from '@cnamts/synapse'
3114
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
3115
+ import type { DataOptions } from '@cnamts/synapse/src/components/Tables/common/types'
3116
+
3117
+ interface User {
3118
+ [key: string]: string
3119
+ firstname: string
3120
+ lastname: string
3121
+ email: string
3122
+ }
3123
+
3124
+ interface DataObj {
3125
+ items: User[]
3126
+ total: number
3127
+ }
3128
+
3129
+ const headers = [
3130
+ { title: 'Nom', key: 'lastname' },
3131
+ { title: 'Prénom', key: 'firstname' },
3132
+ { title: 'Email', key: 'email' },
3133
+ ]
3134
+
3135
+ // Table 1
3136
+ const totalUsersTable1 = ref(0)
3137
+ const usersTable1 = ref<User[]>([])
3138
+ const stateTable1 = ref(StateEnum.IDLE)
3139
+ const optionsTable1 = ref<DataOptions>({
3140
+ itemsPerPage: 5,
3141
+ sortBy: [{ key: 'lastname', order: 'asc' }],
3142
+ page: 1,
3143
+ })
3144
+
3145
+ const fetchDataTable1 = async (options?: DataOptions): Promise<void> => {
3146
+ const optionsToUse = options || optionsTable1.value
3147
+ const { items, total } = await getDataFromApi(optionsToUse)
3148
+ usersTable1.value = items
3149
+ totalUsersTable1.value = total
3150
+ }
3151
+
3152
+ // Table 2
3153
+ const totalUsersTable2 = ref(0)
3154
+ const usersTable2 = ref<User[]>([])
3155
+ const stateTable2 = ref(StateEnum.IDLE)
3156
+ const optionsTable2 = ref<DataOptions>({
3157
+ itemsPerPage: 3,
3158
+ sortBy: [{ key: 'firstname', order: 'asc' }],
3159
+ page: 1,
3160
+ })
3161
+
3162
+ const fetchDataTable2 = async (options?: DataOptions): Promise<void> => {
3163
+ const optionsToUse = options || optionsTable2.value
3164
+ const { items, total } = await getDataFromApi(optionsToUse)
3165
+ usersTable2.value = items
3166
+ totalUsersTable2.value = total
3167
+ }
3168
+
3169
+ const wait = async (ms: number) => {
3170
+ return new Promise(resolve => setTimeout(resolve, ms))
3171
+ }
3172
+
3173
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise<DataObj> => {
3174
+ const state = sortBy[0].key === 'lastname' ? stateTable1 : stateTable2
3175
+ state.value = StateEnum.PENDING
3176
+ await wait(1000)
3177
+
3178
+ return new Promise((resolve) => {
3179
+ let items: User[] = getUsers()
3180
+ const total = items.length
3181
+
3182
+ if (sortBy && sortBy.length > 0) {
3183
+ items = items.sort((a, b) => {
3184
+ const key = sortBy[0].key
3185
+ const order = sortBy[0].order === 'asc' ? 1 : -1
3186
+
3187
+ return a[key] > b[key] ? order : -order
3188
+ })
3189
+ }
3190
+
3191
+ if (itemsPerPage > 0) {
3192
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
3193
+ }
3194
+
3195
+ resolve({ items, total })
3196
+ state.value = StateEnum.RESOLVED
3197
+ })
3198
+ }
3199
+
3200
+ const getUsers = (): User[] => {
3201
+ return [
3202
+ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
3203
+ { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
3204
+ { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
3205
+ { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
3206
+ { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
3207
+ { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
3208
+ { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
3209
+ { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
3210
+ { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
3211
+ { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
3212
+ ]
3213
+ }
3214
+
3215
+ fetchDataTable1()
3216
+ fetchDataTable2()
3217
+ </script>
3218
+ `,
3219
+ },
3220
+ ],
3221
+ },
3222
+ args: {
3223
+ 'serverItemsLength': 15, // Add required serverItemsLength property
3224
+ 'headers': [
3225
+ { title: 'Nom', key: 'lastname' },
3226
+ { title: 'Prénom', key: 'firstname' },
3227
+ { title: 'Email', key: 'email' },
3228
+ ],
3229
+ 'caption': '',
3230
+ 'suffix': 'multi',
3231
+ 'density': 'default',
3232
+ 'striped': false,
3233
+ 'onUpdate:options': fn(),
3234
+ },
3235
+ render: (args) => {
3236
+ return {
3237
+ components: { SyServerTable },
3238
+ setup() {
3239
+ // Table 1
3240
+ const totalUsersTable1 = ref(0)
3241
+ const usersTable1 = ref<User[]>([])
3242
+ const stateTable1 = ref(StateEnum.IDLE)
3243
+
3244
+ const optionsTable1 = ref<Partial<DataOptions>>({
3245
+ itemsPerPage: 5,
3246
+ sortBy: [{ key: 'lastname', order: 'asc' }],
3247
+ page: 1,
3248
+ })
3249
+
3250
+ const fetchDataTable1 = async (options?: DataOptions): Promise<void> => {
3251
+ const optionsToUse = options || optionsTable1.value as DataOptions
3252
+ const { items, total } = await getDataFromApi(optionsToUse)
3253
+ usersTable1.value = items
3254
+ totalUsersTable1.value = total
3255
+ }
3256
+
3257
+ // Table 2
3258
+ const totalUsersTable2 = ref(0)
3259
+ const usersTable2 = ref<User[]>([])
3260
+ const stateTable2 = ref(StateEnum.IDLE)
3261
+
3262
+ const optionsTable2 = ref<Partial<DataOptions>>({
3263
+ itemsPerPage: 3,
3264
+ sortBy: [{ key: 'firstname', order: 'asc' }],
3265
+ page: 1,
3266
+ })
3267
+
3268
+ const fetchDataTable2 = async (options?: DataOptions): Promise<void> => {
3269
+ const optionsToUse = options || optionsTable2.value as DataOptions
3270
+ const { items, total } = await getDataFromApi(optionsToUse)
3271
+ usersTable2.value = items
3272
+ totalUsersTable2.value = total
3273
+ }
3274
+
3275
+ const wait = async (ms: number) => {
3276
+ return new Promise(resolve => setTimeout(resolve, ms))
3277
+ }
3278
+
3279
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise<DataObj> => {
3280
+ const state = sortBy[0].key === 'lastname' ? stateTable1 : stateTable2
3281
+ state.value = StateEnum.PENDING
3282
+ await wait(1000)
3283
+
3284
+ return new Promise((resolve) => {
3285
+ let items: User[] = getUsers()
3286
+ const total = items.length
3287
+
3288
+ if (sortBy && sortBy.length > 0) {
3289
+ items = items.sort((a, b) => {
3290
+ const key = sortBy[0].key
3291
+ const order = sortBy[0].order === 'asc' ? 1 : -1
3292
+
3293
+ return a[key] > b[key] ? order : -order
3294
+ })
3295
+ }
3296
+
3297
+ if (itemsPerPage > 0) {
3298
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
3299
+ }
3300
+
3301
+ resolve({ items, total })
3302
+ state.value = StateEnum.RESOLVED
3303
+ })
3304
+ }
3305
+
3306
+ const getUsers = (): User[] => {
3307
+ return [
3308
+ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
3309
+ { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
3310
+ { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
3311
+ { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
3312
+ { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
3313
+ { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
3314
+ { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
3315
+ { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
3316
+ { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
3317
+ { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
3318
+ ]
3319
+ }
3320
+
3321
+ // Chargement initial des données
3322
+ fetchDataTable1()
3323
+ fetchDataTable2()
3324
+
3325
+ return {
3326
+ args,
3327
+ usersTable1,
3328
+ totalUsersTable1,
3329
+ optionsTable1,
3330
+ stateTable1,
3331
+ fetchDataTable1,
3332
+ usersTable2,
3333
+ totalUsersTable2,
3334
+ optionsTable2,
3335
+ stateTable2,
3336
+ fetchDataTable2,
3337
+ StateEnum,
3338
+ }
3339
+ },
3340
+ template: `
3341
+ <div>
3342
+ <SyServerTable
3343
+ v-bind="args"
3344
+ v-model:options="optionsTable1"
3345
+ :items="usersTable1"
3346
+ :server-items-length="totalUsersTable1"
3347
+ :loading="stateTable1 === StateEnum.PENDING"
3348
+ suffix="table1"
3349
+ class="mb-10"
3350
+ @update:options="fetchDataTable1"
3351
+ />
3352
+ <SyServerTable
3353
+ v-bind="args"
3354
+ v-model:options="optionsTable2"
3355
+ :items="usersTable2"
3356
+ :server-items-length="totalUsersTable2"
3357
+ :loading="stateTable2 === StateEnum.PENDING"
3358
+ suffix="table2"
3359
+ @update:options="fetchDataTable2"
3360
+ />
3361
+ </div>
3362
+ `,
3363
+ }
3364
+ },
3365
+ }
3366
+
3367
+ export const DataAlignment: Story = {
3368
+ parameters: {
3369
+ sourceCode: [
3370
+ {
3371
+ name: 'Template',
3372
+ code: `
3373
+ <template>
3374
+ <SyServerTable
3375
+ v-model:options="options"
3376
+ :items="users"
3377
+ :headers="headers"
3378
+ :server-items-length="totalUsers"
3379
+ :loading="state === StateEnum.PENDING"
3380
+ suffix="server-resizable-columns"
3381
+ @update:options="fetchData"
3382
+ />
3383
+ </template>
3384
+ `,
3385
+ },
3386
+ {
3387
+ name: 'Script',
3388
+ code: `
3389
+ <script setup lang="ts">
3390
+ import { ref, watch } from 'vue'
3391
+ import { SyServerTable } from '@cnamts/synapse'
3392
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
3393
+ import type { DataOptions } from '@cnamts/synapse/src/components/Tables/common/types'
3394
+
3395
+ const totalUsers = ref(0)
3396
+ const users = ref<User[]>([])
3397
+ const state = ref(StateEnum.IDLE)
3398
+
3399
+ const options = ref({
3400
+ itemsPerPage: 5,
3401
+ sortBy: [{ key: 'lastname', order: 'asc' }],
3402
+ page: 1,
3403
+ })
3404
+
3405
+ const headers = [
3406
+ {
3407
+ title: 'ID',
3408
+ key: 'id',
3409
+ align: 'center',
3410
+ },
3411
+ {
3412
+ title: 'Nom',
3413
+ key: 'lastname',
3414
+ align: 'start',
3415
+ },
3416
+ {
3417
+ title: 'Date de naissance',
3418
+ key: 'birthdate',
3419
+ align: 'center',
3420
+ },
3421
+ {
3422
+ title: 'NIR',
3423
+ key: 'nir',
3424
+ align: 'end',
3425
+ },
3426
+ ]
3427
+
3428
+ const fetchData = async (): Promise<void> => {
3429
+ const { items, total } = await getDataFromApi(options.value)
3430
+ users.value = items
3431
+ totalUsers.value = total
3432
+ }
3433
+
3434
+ const wait = async (ms: number) => {
3435
+ return new Promise(resolve => setTimeout(resolve, ms))
3436
+ }
3437
+
3438
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions) => {
3439
+ state.value = StateEnum.PENDING
3440
+ await wait(1000)
3441
+
3442
+ return new Promise((resolve) => {
3443
+ let items: User[] = getUsers()
3444
+ const total = items.length
3445
+
3446
+ if (sortBy && sortBy.length > 0) {
3447
+ items = items.sort((a, b) => {
3448
+ const key = sortBy[0].key
3449
+ const order = sortBy[0].order === 'asc' ? 1 : -1
3450
+
3451
+ return a[key] > b[key] ? order : -order
3452
+ })
3453
+ }
3454
+
3455
+ if (itemsPerPage > 0) {
3456
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
3457
+ }
3458
+
3459
+ resolve({ items, total })
3460
+ state.value = StateEnum.RESOLVED
3461
+ })
3462
+ }
3463
+
3464
+ const getUsers = () => {
3465
+ return [
3466
+ {
3467
+ id: '1',
3468
+ lastname: 'Lefebvre',
3469
+ birthdate: '18/02/1989',
3470
+ nir: '1 89 02 75 120 005 79',
3471
+ },
3472
+ {
3473
+ id: '2',
3474
+ lastname: 'Richard',
3475
+ birthdate: '22/05/1991',
3476
+ nir: '2 91 05 75 120 005 76',
3477
+ },
3478
+ {
3479
+ id: '3',
3480
+ lastname: 'Fournier',
3481
+ birthdate: '11/11/2000',
3482
+ nir: '2 00 11 42 120 008 87',
3483
+ },
3484
+ ]
3485
+ }
3486
+
3487
+ fetchData()
3488
+ </script>
3489
+ `,
3490
+ },
3491
+ ],
3492
+ },
3493
+ args: {
3494
+ 'options': {
3495
+ itemsPerPage: 5,
3496
+ sortBy: [{ key: 'lastname', order: 'asc' }],
3497
+ page: 1,
3498
+ },
3499
+ 'headers': [
3500
+ {
3501
+ title: 'ID',
3502
+ key: 'id',
3503
+ align: 'center',
3504
+ },
3505
+ {
3506
+ title: 'Nom',
3507
+ key: 'lastname',
3508
+ align: 'start',
3509
+ },
3510
+ {
3511
+ title: 'Date de naissance',
3512
+ key: 'birthdate',
3513
+ align: 'center',
3514
+ },
3515
+ {
3516
+ title: 'NIR',
3517
+ key: 'nir',
3518
+ align: 'end',
3519
+ },
3520
+ ],
3521
+ 'caption': '',
3522
+ 'serverItemsLength': 3,
3523
+ 'suffix': 'server-resizable-columns',
3524
+ 'density': 'default',
3525
+ 'striped': false,
3526
+ 'onUpdate:options': fn(),
3527
+ },
3528
+ render: (args) => {
3529
+ return {
3530
+ components: { SyServerTable },
3531
+ setup() {
3532
+ const totalUsers = ref(0)
3533
+ const users = ref<User[]>([])
3534
+ const state = ref(StateEnum.IDLE)
3535
+
3536
+ const options = ref({ ...args.options })
3537
+
3538
+ watch(options, (newVal) => {
3539
+ if (args.options) {
3540
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
3541
+ }
3542
+ }, { deep: true })
3543
+
3544
+ const fetchData = async (): Promise<void> => {
3545
+ // @ts-expect-error - fetchData is not defined
3546
+ const { items, total } = await getDataFromApi(options.value)
3547
+ users.value = items
3548
+ totalUsers.value = total
3549
+ }
3550
+
3551
+ const wait = async (ms: number) => {
3552
+ return new Promise(resolve => setTimeout(resolve, ms))
3553
+ }
3554
+
3555
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions) => {
3556
+ state.value = StateEnum.PENDING
3557
+ await wait(1000)
3558
+
3559
+ return new Promise((resolve) => {
3560
+ let items = getUsers()
3561
+ const total = items.length
3562
+
3563
+ if (sortBy && sortBy.length > 0) {
3564
+ items = items.sort((a, b) => {
3565
+ const key = sortBy[0].key
3566
+ const order = sortBy[0].order === 'asc' ? 1 : -1
3567
+
3568
+ return a[key] > b[key] ? order : -order
3569
+ })
3570
+ }
3571
+
3572
+ if (itemsPerPage > 0) {
3573
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
3574
+ }
3575
+
3576
+ resolve({ items, total })
3577
+ state.value = StateEnum.RESOLVED
3578
+ })
3579
+ }
3580
+
3581
+ const getUsers = () => {
3582
+ return [
3583
+ {
3584
+ id: '1',
3585
+ lastname: 'Lefebvre',
3586
+ birthdate: '18/02/1989',
3587
+ nir: '1 89 02 75 120 005 79',
3588
+ },
3589
+ {
3590
+ id: '2',
3591
+ lastname: 'Richard',
3592
+ birthdate: '22/05/1991',
3593
+ nir: '2 91 05 75 120 005 76',
3594
+ },
3595
+ {
3596
+ id: '3',
3597
+ lastname: 'Fournier',
3598
+ birthdate: '11/11/2000',
3599
+ nir: '2 00 11 42 120 008 87',
3600
+ },
3601
+ ]
3602
+ }
3603
+
3604
+ fetchData()
3605
+
3606
+ return { args, users, state, fetchData, options, totalUsers, StateEnum }
3607
+ },
3608
+ template: `
3609
+ <SyServerTable
3610
+ v-bind="args"
3611
+ v-model:options="options"
3612
+ :items="users"
3613
+ :server-items-length="totalUsers"
3614
+ :loading="state === StateEnum.PENDING"
3615
+ suffix="server-data-alignment"
3616
+ @update:options="[fetchData, args['onUpdate:options']]"
3617
+ />
3618
+ `,
3619
+ }
3620
+ },
3621
+ }
3622
+
3623
+ export const ResizableColumns: Story = {
3624
+ parameters: {
3625
+ sourceCode: [
3626
+ {
3627
+ name: 'Template',
3628
+ code: `
3629
+ <template>
3630
+ <SyServerTable
3631
+ v-model:options="options"
3632
+ :items="users"
3633
+ :headers="headers"
3634
+ :server-items-length="totalUsers"
3635
+ :loading="state === StateEnum.PENDING"
3636
+ :resizable-columns="true"
3637
+ suffix="server-resizable-columns"
3638
+ @update:options="fetchData"
3639
+ />
3640
+ </template>
3641
+ `,
3642
+ },
3643
+ {
3644
+ name: 'Script',
3645
+ code: `
3646
+ <script setup lang="ts">
3647
+ import { ref, watch } from 'vue'
3648
+ import { SyServerTable } from '@cnamts/synapse'
3649
+ import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
3650
+ import type { DataOptions } from '@cnamts/synapse/src/components/Tables/common/types'
3651
+
3652
+ interface User {
3653
+ [key: string]: string
3654
+ firstname: string
3655
+ lastname: string
3656
+ email: string
3657
+ }
3658
+
3659
+ interface DataObj {
3660
+ items: User[]
3661
+ total: number
3662
+ }
3663
+
3664
+ const totalUsers = ref(0)
3665
+ const users = ref<User[]>([])
3666
+ const state = ref(StateEnum.IDLE)
3667
+
3668
+ const options = ref({
3669
+ itemsPerPage: 5,
3670
+ sortBy: [{ key: 'lastname', order: 'asc' }],
3671
+ page: 1,
3672
+ })
3673
+
3674
+ const headers = [
3675
+ { title: 'Nom', key: 'lastname' },
3676
+ { title: 'Prénom', key: 'firstname' },
3677
+ { title: 'Email', key: 'email' },
3678
+ ]
3679
+
3680
+ const fetchData = async (): Promise<void> => {
3681
+ const { items, total } = await getDataFromApi(options.value)
3682
+ users.value = items
3683
+ totalUsers.value = total
3684
+ }
3685
+
3686
+ const wait = async (ms: number) => {
3687
+ return new Promise(resolve => setTimeout(resolve, ms))
3688
+ }
3689
+
3690
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
3691
+ state.value = StateEnum.PENDING
3692
+ await wait(1000)
3693
+
3694
+ return new Promise((resolve) => {
3695
+ let items: User[] = getUsers()
3696
+ const total = items.length
3697
+
3698
+ if (sortBy && sortBy.length > 0) {
3699
+ items = items.sort((a, b) => {
3700
+ const key = sortBy[0].key
3701
+ const order = sortBy[0].order === 'asc' ? 1 : -1
3702
+
3703
+ return a[key] > b[key] ? order : -order
3704
+ })
3705
+ }
3706
+
3707
+ if (itemsPerPage > 0) {
3708
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
3709
+ }
3710
+
3711
+ resolve({ items, total })
3712
+ state.value = StateEnum.RESOLVED
3713
+ })
3714
+ }
3715
+
3716
+ const getUsers = (): User[] => {
3717
+ return [
3718
+ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
3719
+ { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
3720
+ { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
3721
+ { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
3722
+ { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
3723
+ { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
3724
+ { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
3725
+ { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
3726
+ { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
3727
+ { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
3728
+ { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' },
3729
+ { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' },
3730
+ { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' },
3731
+ { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' },
3732
+ { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' },
3733
+ ]
3734
+ }
3735
+
3736
+ fetchData()
3737
+ </script>
3738
+ `,
3739
+ },
3740
+ ],
3741
+ },
3742
+ args: {
3743
+ 'options': {
3744
+ itemsPerPage: 5,
3745
+ sortBy: [{ key: 'lastname', order: 'asc' }],
3746
+ page: 1,
3747
+ },
3748
+ 'headers': [
3749
+ { title: 'Nom', key: 'lastname' },
3750
+ { title: 'Prénom', key: 'firstname' },
3751
+ { title: 'Email', key: 'email' },
3752
+ ],
3753
+ 'caption': '',
3754
+ 'serverItemsLength': 15,
3755
+ 'suffix': 'server-resizable-columns',
3756
+ 'density': 'default',
3757
+ 'striped': false,
3758
+ 'resizableColumns': true,
3759
+ 'onUpdate:options': fn(),
3760
+ },
3761
+ render: (args) => {
3762
+ return {
3763
+ components: { SyServerTable },
3764
+ setup() {
3765
+ const totalUsers = ref(0)
3766
+ const users = ref<User[]>([])
3767
+ const state = ref(StateEnum.IDLE)
3768
+
3769
+ const options = ref({ ...args.options })
3770
+
3771
+ watch(options, (newVal) => {
3772
+ if (args.options) {
3773
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
3774
+ }
3775
+ }, { deep: true })
3776
+
3777
+ const fetchData = async (): Promise<void> => {
3778
+ // @ts-expect-error - fetchData is not defined
3779
+ const { items, total } = await getDataFromApi(options.value)
3780
+ users.value = items
3781
+ totalUsers.value = total
3782
+ }
3783
+
3784
+ const wait = async (ms: number) => {
3785
+ return new Promise(resolve => setTimeout(resolve, ms))
3786
+ }
3787
+
3788
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise<DataObj> => {
3789
+ state.value = StateEnum.PENDING
3790
+ await wait(1000)
3791
+
3792
+ return new Promise((resolve) => {
3793
+ let items: User[] = getUsers()
3794
+ const total = items.length
3795
+
3796
+ if (sortBy && sortBy.length > 0) {
3797
+ items = items.sort((a, b) => {
3798
+ const key = sortBy[0].key
3799
+ const order = sortBy[0].order === 'asc' ? 1 : -1
3800
+
3801
+ return a[key] > b[key] ? order : -order
3802
+ })
3803
+ }
3804
+
3805
+ if (itemsPerPage > 0) {
3806
+ items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
3807
+ }
3808
+
3809
+ resolve({ items, total })
3810
+ state.value = StateEnum.RESOLVED
3811
+ })
3812
+ }
3813
+
3814
+ const getUsers = (): User[] => {
3815
+ return [
2304
3816
  { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
2305
3817
  { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
2306
3818
  { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
@@ -2311,275 +3823,237 @@ export const CustomFilterInputs: Story = {
2311
3823
  { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
2312
3824
  { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
2313
3825
  { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
2314
- { firstname: 'Martin', lastname: 'Lavoie', email: 'martin.lavoie@example.com' },
2315
- { firstname: 'Céline', lastname: 'Tremblay', email: 'celine.tremblay@example.com' },
2316
- { firstname: 'Jacques', lastname: 'Gagnon', email: 'jacques.gagnon@example.com' },
2317
- { firstname: 'Isabelle', lastname: 'Côté', email: 'isabelle.cote@example.com' },
2318
- { firstname: 'Philippe', lastname: 'Bouchard', email: 'philippe.bouchard@example.com' },
3826
+ { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' },
3827
+ { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' },
3828
+ { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' },
3829
+ { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' },
3830
+ { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' },
2319
3831
  ]
2320
-
2321
- // Apply filters on server side
2322
- if (options.value?.filters && options.value.filters.length > 0) {
2323
- options.value.filters.forEach((filter) => {
2324
- const { key, value } = filter
2325
-
2326
- items = items.filter((item) => {
2327
- const itemValue = item[key]
2328
- return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
2329
- })
2330
- })
2331
- }
2332
-
2333
- const total = items.length
2334
-
2335
- // Apply pagination
2336
- const { page = 1, itemsPerPage = 10 } = options.value || {}
2337
- if (itemsPerPage > 0) {
2338
- items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
2339
- }
2340
-
2341
- filteredUsers.value = items as Record<string, unknown>[]
2342
- totalFilteredUsers.value = total
2343
- state.value = StateEnum.RESOLVED
2344
3832
  }
2345
3833
 
2346
- // Initialize data
2347
3834
  fetchData()
2348
3835
 
2349
- return {
2350
- args,
2351
- options,
2352
- filteredUsers,
2353
- totalFilteredUsers,
2354
- state,
2355
- fetchData,
2356
- StateEnum,
2357
- }
3836
+ return { args, users, state, fetchData, options, totalUsers, StateEnum }
2358
3837
  },
2359
3838
  template: `
2360
- <div>
2361
- <SyServerTable
2362
- v-model:options="options"
2363
- :items="filteredUsers"
2364
- :headers="args.headers"
2365
- :caption="args.caption"
2366
- :server-items-length="totalFilteredUsers"
2367
- :loading="state === StateEnum.PENDING"
2368
- :show-filters="args.showFilters"
2369
- :filter-input-config="args.filterInputConfig"
2370
- :suffix="args.suffix"
2371
- :density="args.density"
2372
- :striped="args.striped"
2373
- :resizable-columns="args.resizableColumns"
2374
- @update:options="fetchData"
2375
- />
2376
- </div>
3839
+ <div>
3840
+ <SyServerTable
3841
+ v-bind="args"
3842
+ v-model:options="options"
3843
+ :items="users"
3844
+ :server-items-length="totalUsers"
3845
+ :loading="state === StateEnum.PENDING"
3846
+ suffix="server-resizable-columns"
3847
+ @update:options="fetchData"
3848
+ />
3849
+ </div>
2377
3850
  `,
2378
3851
  }
2379
3852
  },
2380
3853
  }
2381
3854
 
2382
- export const ManyServerTables: Story = {
3855
+ export const RowSelection: Story = {
3856
+ name: 'Row Selection',
2383
3857
  parameters: {
2384
3858
  sourceCode: [
2385
3859
  {
2386
3860
  name: 'Template',
2387
3861
  code: `
2388
- <template>
2389
- <div>
2390
- <SyServerTable
2391
- v-model:options="optionsTable1"
2392
- :items="usersTable1"
2393
- :headers="headers"
2394
- :server-items-length="totalUsersTable1"
2395
- :loading="stateTable1 === StateEnum.PENDING"
2396
- suffix="table1"
2397
- @update:options="fetchDataTable1"
2398
- />
2399
- <SyServerTable
2400
- v-model:options="optionsTable2"
2401
- :items="usersTable2"
2402
- :headers="headers"
2403
- :server-items-length="totalUsersTable2"
2404
- :loading="stateTable2 === StateEnum.PENDING"
2405
- suffix="table2"
2406
- @update:options="fetchDataTable2"
2407
- />
2408
- </div>
2409
- </template>
2410
- `,
3862
+ <template>
3863
+ <SyServerTable
3864
+ v-model:options="options"
3865
+ v-model="selection"
3866
+ :headers="headers"
3867
+ :items="items"
3868
+ :serverItemsLength="items.length"
3869
+ show-select
3870
+ show-filters
3871
+ suffix="selection-server-table"
3872
+ />
3873
+ <div v-if="selection.length" class="mt-4 pa-4 bg-grey-lighten-4">
3874
+ <h3 class="text-h6 mb-3">Item(s) sélectionné(s) ({{ selection.length }})</h3>
3875
+ <div v-for="(item, index) in selection" :key="index" class="mb-2 pa-2 bg-grey-lighten-3">
3876
+ <div><strong>Nom:</strong> {{ typeof item === 'object' ? item.lastname : users.find(i => JSON.stringify(i) === item)?.lastname }}</div>
3877
+ <div><strong>Prénom:</strong> {{ typeof item === 'object' ? item.firstname : users.find(i => JSON.stringify(i) === item)?.firstname }}</div>
3878
+ <div><strong>Email:</strong> {{ typeof item === 'object' ? item.email : users.find(i => JSON.stringify(i) === item)?.email }}</div>
3879
+ </div>
3880
+ </div>
3881
+ </div>
3882
+ </template>
3883
+ `,
2411
3884
  },
2412
3885
  {
2413
3886
  name: 'Script',
2414
3887
  code: `
2415
- <script setup lang="ts">
2416
- import { ref } from 'vue'
2417
- import { SyServerTable } from '@cnamts/synapse'
2418
- import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
2419
- import type { DataOptions } from '@cnamts/synapse/src/components/Tables/common/types'
2420
-
2421
- interface User {
2422
- [key: string]: string
2423
- firstname: string
2424
- lastname: string
2425
- email: string
2426
- }
2427
-
2428
- interface DataObj {
2429
- items: User[]
2430
- total: number
2431
- }
2432
-
2433
- const headers = [
2434
- { title: 'Nom', key: 'lastname' },
2435
- { title: 'Prénom', key: 'firstname' },
2436
- { title: 'Email', key: 'email' },
2437
- ]
2438
-
2439
- // Table 1
2440
- const totalUsersTable1 = ref(0)
2441
- const usersTable1 = ref<User[]>([])
2442
- const stateTable1 = ref(StateEnum.IDLE)
2443
- const optionsTable1 = ref<DataOptions>({
2444
- itemsPerPage: 5,
2445
- sortBy: [{ key: 'lastname', order: 'asc' }],
2446
- page: 1,
2447
- })
2448
-
2449
- const fetchDataTable1 = async (): Promise<void> => {
2450
- const { items, total } = await getDataFromApi(optionsTable1.value)
2451
- usersTable1.value = items
2452
- totalUsersTable1.value = total
2453
- }
2454
-
2455
- // Table 2
2456
- const totalUsersTable2 = ref(0)
2457
- const usersTable2 = ref<User[]>([])
2458
- const stateTable2 = ref(StateEnum.IDLE)
2459
- const optionsTable2 = ref<DataOptions>({
2460
- itemsPerPage: 3,
2461
- sortBy: [{ key: 'firstname', order: 'asc' }],
2462
- page: 1,
2463
- })
2464
-
2465
- const fetchDataTable2 = async (): Promise<void> => {
2466
- const { items, total } = await getDataFromApi(optionsTable2.value)
2467
- usersTable2.value = items
2468
- totalUsersTable2.value = total
2469
- }
2470
-
2471
- const wait = async (ms: number) => {
2472
- return new Promise(resolve => setTimeout(resolve, ms))
2473
- }
2474
-
2475
- const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise<DataObj> => {
2476
- const state = sortBy[0].key === 'lastname' ? stateTable1 : stateTable2
2477
- state.value = StateEnum.PENDING
2478
- await wait(1000)
2479
-
2480
- return new Promise((resolve) => {
2481
- let items: User[] = getUsers()
2482
- const total = items.length
2483
-
2484
- if (sortBy && sortBy.length > 0) {
2485
- items = items.sort((a, b) => {
2486
- const key = sortBy[0].key
2487
- const order = sortBy[0].order === 'asc' ? 1 : -1
2488
-
2489
- return a[key] > b[key] ? order : -order
2490
- })
2491
- }
2492
-
2493
- if (itemsPerPage > 0) {
2494
- items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
2495
- }
2496
-
2497
- resolve({ items, total })
2498
- state.value = StateEnum.RESOLVED
2499
- })
2500
- }
2501
-
2502
- const getUsers = (): User[] => {
2503
- return [
2504
- { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
2505
- { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
2506
- { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
2507
- { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
2508
- { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
2509
- { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
2510
- { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
2511
- { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
2512
- { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
2513
- { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
2514
- ]
2515
- }
2516
- </script>
2517
- `,
3888
+ <script setup lang="ts">
3889
+ import { ref } from 'vue'
3890
+ import { SyServerTable } from '@cnamts/synapse'
3891
+
3892
+ const options = ref({
3893
+ itemsPerPage: 4,
3894
+ })
3895
+
3896
+ const headers = ref([
3897
+ {
3898
+ title: 'Nom',
3899
+ key: 'lastname',
3900
+ },
3901
+ {
3902
+ title: 'Prénom',
3903
+ key: 'firstname',
3904
+ },
3905
+ {
3906
+ title: 'Email',
3907
+ value: 'email',
3908
+ },
3909
+ ])
3910
+
3911
+ const items = ref([
3912
+ {
3913
+ firstname: 'Virginie',
3914
+ lastname: 'Beauchesne',
3915
+ email: 'virginie.beauchesne@example.com',
3916
+ },
3917
+ {
3918
+ firstname: 'Simone',
3919
+ lastname: 'Bellefeuille',
3920
+ email: 'simone.bellefeuille@example.com',
3921
+ },
3922
+ {
3923
+ firstname: 'Étienne',
3924
+ lastname: 'Salois',
3925
+ email: 'etienne.salois@example.com',
3926
+ },
3927
+ {
3928
+ firstname: 'Thierry',
3929
+ lastname: 'Bobu',
3930
+ email: 'thierry.bobu@example.com',
3931
+ },
3932
+ {
3933
+ firstname: 'Bernadette',
3934
+ lastname: 'Langelier',
3935
+ email: 'bernadette.langelier@exemple.com'
3936
+ },
3937
+ {
3938
+ firstname: 'Agate',
3939
+ lastname: 'Roy',
3940
+ email: 'agate.roy@exemple.com'
3941
+ }
3942
+ ])
3943
+ </script>
3944
+ `,
2518
3945
  },
2519
3946
  ],
2520
3947
  },
2521
3948
  args: {
2522
- serverItemsLength: 15,
2523
- headers: [
2524
- { title: 'Nom', key: 'lastname' },
2525
- { title: 'Prénom', key: 'firstname' },
2526
- { title: 'Email', key: 'email' },
3949
+ 'headers': [
3950
+ {
3951
+ title: 'Nom',
3952
+ key: 'lastname',
3953
+ },
3954
+ {
3955
+ title: 'Prénom',
3956
+ key: 'firstname',
3957
+ },
3958
+ {
3959
+ title: 'Email',
3960
+ value: 'email',
3961
+ },
3962
+ ],
3963
+ 'items': [
3964
+ {
3965
+ firstname: 'Virginie',
3966
+ lastname: 'Beauchesne',
3967
+ email: 'virginie.beauchesne@example.com',
3968
+ },
3969
+ {
3970
+ firstname: 'Simone',
3971
+ lastname: 'Bellefeuille',
3972
+ email: 'simone.bellefeuille@example.com',
3973
+ },
3974
+ {
3975
+ firstname: 'Étienne',
3976
+ lastname: 'Salois',
3977
+ email: 'etienne.salois@example.com',
3978
+ },
3979
+ {
3980
+ firstname: 'Thierry',
3981
+ lastname: 'Bobu',
3982
+ email: 'thierry.bobu@example.com',
3983
+ },
3984
+ {
3985
+ firstname: 'Bernadette',
3986
+ lastname: 'Langelier',
3987
+ email: 'bernadette.langelier@exemple.com',
3988
+ },
3989
+ {
3990
+ firstname: 'Agate',
3991
+ lastname: 'Roy',
3992
+ email: 'agate.roy@exemple.com',
3993
+ },
2527
3994
  ],
2528
- caption: '',
2529
- suffix: 'multi',
2530
- density: 'default',
2531
- striped: false,
3995
+ 'options': {
3996
+ itemsPerPage: 4,
3997
+ page: 1,
3998
+ filters: [],
3999
+ },
4000
+ 'caption': '',
4001
+ 'suffix': 'selection-server-table',
4002
+ 'density': 'default',
4003
+ 'striped': false,
4004
+ 'showSelect': true,
4005
+ 'showFilters': true,
4006
+ 'serverItemsLength': 6,
4007
+ 'onUpdate:options': fn(),
2532
4008
  },
2533
- render: (args) => {
4009
+ render(args) {
2534
4010
  return {
2535
4011
  components: { SyServerTable },
2536
4012
  setup() {
2537
- // Table 1
2538
- const totalUsersTable1 = ref(0)
2539
- const usersTable1 = ref<User[]>([])
2540
- const stateTable1 = ref(StateEnum.IDLE)
2541
-
2542
- const optionsTable1 = ref<Partial<DataOptions>>({
2543
- itemsPerPage: 5,
2544
- sortBy: [{ key: 'lastname', order: 'asc' }],
2545
- page: 1,
2546
- })
2547
-
2548
- const fetchDataTable1 = async (): Promise<void> => {
2549
- const { items, total } = await getDataFromApi(optionsTable1.value as DataOptions)
2550
- usersTable1.value = items
2551
- totalUsersTable1.value = total
2552
- }
2553
-
2554
- // Table 2
2555
- const totalUsersTable2 = ref(0)
2556
- const usersTable2 = ref<User[]>([])
2557
- const stateTable2 = ref(StateEnum.IDLE)
2558
-
2559
- const optionsTable2 = ref<Partial<DataOptions>>({
2560
- itemsPerPage: 3,
2561
- sortBy: [{ key: 'firstname', order: 'asc' }],
2562
- page: 1,
2563
- })
4013
+ const totalUsers = ref(0)
4014
+ const users = ref<User[]>([])
4015
+ const selection = ref([])
4016
+ const state = ref(StateEnum.IDLE)
2564
4017
 
2565
- const fetchDataTable2 = async (): Promise<void> => {
2566
- const { items, total } = await getDataFromApi(optionsTable2.value as DataOptions)
2567
- usersTable2.value = items
2568
- totalUsersTable2.value = total
4018
+ const fetchData = async (): Promise<void> => {
4019
+ // Create a complete DataOptions object with all required properties
4020
+ const defaultOptions: DataOptions = {
4021
+ page: 1,
4022
+ itemsPerPage: 10,
4023
+ sortBy: [],
4024
+ multiSort: false,
4025
+ }
4026
+ const options = args.options ? { ...defaultOptions, ...args.options } : defaultOptions
4027
+ const { items, total } = await getDataFromApi(options)
4028
+ users.value = items
4029
+ totalUsers.value = total
2569
4030
  }
2570
4031
 
2571
4032
  const wait = async (ms: number) => {
2572
4033
  return new Promise(resolve => setTimeout(resolve, ms))
2573
4034
  }
2574
4035
 
2575
- const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise<DataObj> => {
2576
- const state = sortBy[0].key === 'lastname' ? stateTable1 : stateTable2
4036
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
2577
4037
  state.value = StateEnum.PENDING
2578
4038
  await wait(1000)
2579
4039
 
2580
4040
  return new Promise((resolve) => {
2581
4041
  let items: User[] = getUsers()
2582
- const total = items.length
4042
+ let total = items.length // Changed from const to let
4043
+
4044
+ // Add filtering logic here
4045
+ if (filters && filters.length > 0) {
4046
+ filters.forEach((filter) => {
4047
+ const { key, value } = filter
4048
+
4049
+ items = items.filter((item) => {
4050
+ const itemValue = item[key]
4051
+ return String(itemValue).toLowerCase().includes(String(value).toLowerCase())
4052
+ })
4053
+ })
4054
+ // Update total after filtering
4055
+ total = items.length
4056
+ }
2583
4057
 
2584
4058
  if (sortBy && sortBy.length > 0) {
2585
4059
  items = items.sort((a, b) => {
@@ -2604,66 +4078,50 @@ export const ManyServerTables: Story = {
2604
4078
  { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
2605
4079
  { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
2606
4080
  { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' },
2607
- { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' },
2608
- { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' },
4081
+ { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com' },
4082
+ { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com' },
4083
+ { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com' },
2609
4084
  { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' },
2610
4085
  { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' },
2611
4086
  { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' },
2612
4087
  { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' },
2613
4088
  { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' },
4089
+ { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' },
2614
4090
  ]
2615
4091
  }
2616
4092
 
2617
- return {
2618
- args,
2619
- usersTable1,
2620
- totalUsersTable1,
2621
- optionsTable1,
2622
- stateTable1,
2623
- fetchDataTable1,
2624
- usersTable2,
2625
- totalUsersTable2,
2626
- optionsTable2,
2627
- stateTable2,
2628
- fetchDataTable2,
2629
- StateEnum,
2630
- }
4093
+ // Call fetchData on mount
4094
+ fetchData()
4095
+
4096
+ return { args, users, state, fetchData, totalUsers, selection, StateEnum }
2631
4097
  },
2632
4098
  template: `
2633
- <div>
2634
- <SyServerTable
2635
- v-model:options="optionsTable1"
2636
- :items="usersTable1"
2637
- :headers="args.headers"
2638
- :caption="args.caption"
2639
- :server-items-length="totalUsersTable1"
2640
- :loading="stateTable1 === StateEnum.PENDING"
2641
- :density="args.density"
2642
- :striped="args.striped"
2643
- suffix="table1"
2644
- class="mb-10"
2645
- :resizable-columns="args.resizableColumns"
2646
- @update:options="fetchDataTable1"
2647
- />
2648
- <SyServerTable
2649
- v-model:options="optionsTable2"
2650
- :items="usersTable2"
2651
- :headers="args.headers"
2652
- :caption="args.caption"
2653
- :server-items-length="totalUsersTable2"
2654
- :loading="stateTable2 === StateEnum.PENDING"
2655
- :density="args.density"
2656
- :striped="args.striped"
2657
- suffix="table2"
2658
- :resizable-columns="args.resizableColumns"
2659
- @update:options="fetchDataTable2"
2660
- />
2661
- </div>
2662
- `,
4099
+ <div>
4100
+ <SyServerTable
4101
+ v-bind="args"
4102
+ v-model:options="args.options"
4103
+ v-model="selection"
4104
+ :items="users"
4105
+ :server-items-length="totalUsers"
4106
+ :loading="state === StateEnum.PENDING"
4107
+ suffix="selection-server-table"
4108
+ @update:options="fetchData"
4109
+ />
4110
+ <div v-if="selection.length" class="mt-4 pa-4 bg-grey-lighten-4">
4111
+ <h3 class="text-h6 mb-3">Item(s) sélectionné(s) ({{ selection.length }})</h3>
4112
+ <div v-for="(item, index) in selection" :key="index" class="mb-2 pa-2 bg-grey-lighten-3">
4113
+ <div><strong>Nom:</strong> {{ typeof item === 'object' ? item.lastname : users.find(i => JSON.stringify(i) === item)?.lastname }}</div>
4114
+ <div><strong>Prénom:</strong> {{ typeof item === 'object' ? item.firstname : users.find(i => JSON.stringify(i) === item)?.firstname }}</div>
4115
+ <div><strong>Email:</strong> {{ typeof item === 'object' ? item.email : users.find(i => JSON.stringify(i) === item)?.email }}</div>
4116
+ </div>
4117
+ </div>
4118
+ </div>
4119
+ `,
2663
4120
  }
2664
4121
  },
2665
4122
  }
2666
- export const ResizableColumns: Story = {
4123
+
4124
+ export const ColumnControls: StoryObj<typeof SyServerTable> = {
2667
4125
  parameters: {
2668
4126
  sourceCode: [
2669
4127
  {
@@ -2676,8 +4134,8 @@ export const ResizableColumns: Story = {
2676
4134
  :headers="headers"
2677
4135
  :server-items-length="totalUsers"
2678
4136
  :loading="state === StateEnum.PENDING"
2679
- :resizable-columns="true"
2680
- suffix="server-resizable-columns"
4137
+ suffix="server-control-columns"
4138
+ enable-column-controls
2681
4139
  @update:options="fetchData"
2682
4140
  />
2683
4141
  </template>
@@ -2730,7 +4188,7 @@ export const ResizableColumns: Story = {
2730
4188
  return new Promise(resolve => setTimeout(resolve, ms))
2731
4189
  }
2732
4190
 
2733
- const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise<DataObj> => {
4191
+ const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise<DataObj> => {
2734
4192
  state.value = StateEnum.PENDING
2735
4193
  await wait(1000)
2736
4194
 
@@ -2775,28 +4233,31 @@ export const ResizableColumns: Story = {
2775
4233
  { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' },
2776
4234
  ]
2777
4235
  }
4236
+
4237
+ fetchData()
2778
4238
  </script>
2779
4239
  `,
2780
4240
  },
2781
4241
  ],
2782
4242
  },
2783
4243
  args: {
2784
- options: {
4244
+ 'options': {
2785
4245
  itemsPerPage: 5,
2786
4246
  sortBy: [{ key: 'lastname', order: 'asc' }],
2787
4247
  page: 1,
2788
4248
  },
2789
- headers: [
4249
+ 'headers': [
2790
4250
  { title: 'Nom', key: 'lastname' },
2791
4251
  { title: 'Prénom', key: 'firstname' },
2792
4252
  { title: 'Email', key: 'email' },
2793
4253
  ],
2794
- caption: '',
2795
- serverItemsLength: 15,
2796
- suffix: 'server-resizable-columns',
2797
- density: 'default',
2798
- striped: false,
2799
- resizableColumns: true,
4254
+ 'caption': '',
4255
+ 'serverItemsLength': 15,
4256
+ 'suffix': 'server-control-columns',
4257
+ 'density': 'default',
4258
+ 'striped': false,
4259
+ 'enableColumnControls': true,
4260
+ 'onUpdate:options': fn(),
2800
4261
  },
2801
4262
  render: (args) => {
2802
4263
  return {
@@ -2806,9 +4267,17 @@ export const ResizableColumns: Story = {
2806
4267
  const users = ref<User[]>([])
2807
4268
  const state = ref(StateEnum.IDLE)
2808
4269
 
4270
+ const options = ref({ ...args.options })
4271
+
4272
+ watch(options, (newVal) => {
4273
+ if (args.options) {
4274
+ Object.assign(args.options, JSON.parse(JSON.stringify(newVal)))
4275
+ }
4276
+ }, { deep: true })
4277
+
2809
4278
  const fetchData = async (): Promise<void> => {
2810
4279
  // @ts-expect-error - fetchData is not defined
2811
- const { items, total } = await getDataFromApi(args.options)
4280
+ const { items, total } = await getDataFromApi(options.value)
2812
4281
  users.value = items
2813
4282
  totalUsers.value = total
2814
4283
  }
@@ -2863,21 +4332,19 @@ export const ResizableColumns: Story = {
2863
4332
  ]
2864
4333
  }
2865
4334
 
2866
- return { args, users, state, fetchData, totalUsers, StateEnum }
4335
+ fetchData()
4336
+
4337
+ return { args, users, state, fetchData, options, totalUsers, StateEnum }
2867
4338
  },
2868
4339
  template: `
2869
4340
  <div>
2870
4341
  <SyServerTable
2871
- v-model:options="args.options"
4342
+ v-bind="args"
4343
+ v-model:options="options"
2872
4344
  :items="users"
2873
- :headers="args.headers"
2874
- :caption="args.caption"
2875
4345
  :server-items-length="totalUsers"
2876
4346
  :loading="state === StateEnum.PENDING"
2877
- :suffix="args.suffix"
2878
- :density="args.density"
2879
- :striped="args.striped"
2880
- :resizable-columns="args.resizableColumns"
4347
+ suffix="server-control-columns"
2881
4348
  @update:options="fetchData"
2882
4349
  />
2883
4350
  </div>