import type { Meta, StoryObj } from '@storybook/vue3' import SyServerTable from './SyServerTable.vue' import { StateEnum } from '../common/constants/StateEnum' import type { DataOptions, FilterType } from '../common/types' import { computed, defineComponent, ref, watch } from 'vue' import type { VDataTable } from 'vuetify/components' import dayjs from 'dayjs' import { fn } from '@storybook/test' import { mdiChevronDown, mdiChevronUp } from '@mdi/js' interface User { [key: string]: string firstname: string lastname: string email: string } interface DataObj { items: User[] total: number } const meta = { title: 'Composants/Tableaux/SyServerTable', component: SyServerTable, decorators: [ () => ({ template: '
', }), ], parameters: { layout: 'fullscreen', }, argTypes: { 'headers': { description: 'Liste des colonnes du tableau (voir : https://vuetifyjs.com/en/api/v-data-table/#props-headers)', control: { type: 'object' }, table: { category: 'props', }, }, 'items': { description: 'Liste des éléments à afficher dans le tableau', control: { type: 'object' }, table: { category: 'props', defaultValue: { summary: 'undefined', }, }, }, 'density': { description: 'Définit la densité du tableau', control: { type: 'select' }, options: ['default', 'comfortable', 'compact'], table: { category: 'props', type: { summary: 'string', detail: `'default' | 'comfortable' | 'compact'` }, }, }, 'striped': { description: 'Affiche les lignes du tableau avec un fond rayé', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, }, }, 'options': { description: 'Options de configuration du tableau', name: 'v-model:options', control: { type: 'object' }, table: { category: 'props', type: { summary: 'DataOptions', detail: '{ page: number, itemsPerPage: number, sortBy: SortOptions[], groupBy?: SortOptions[], multiSort?: boolean, mustSort?: boolean, filters?: FilterOption[] }' }, }, }, 'itemsPerPageOptions': { description: 'Limite les options disponibles dans le sélecteur "itemsPerPage"', control: { type: 'object' }, table: { category: 'props', type: { summary: 'number[]' }, defaultValue: { summary: 'undefined' }, }, }, 'serverItemsLength': { description: 'Nombre total d\'éléments à afficher', control: { type: 'number' }, }, 'saveState': { description: 'Permet d\'activer ou non la sauvegarde des options (pagination, tris, ordre des colonnes) du tableau dans le localStorage. Par défaut, cette fonctionnalité est activée.', control: { type: 'boolean' }, }, 'suffix': { description: 'Suffixe permettant de gérer individuellement le stockage des options d\'un tableau d\'une page à l\'autre. Ce prop est obligatoire pour garantir un stockage unique pour chaque tableau.', control: { type: 'text' }, table: { category: 'props', type: { summary: 'string' }, }, required: true, }, 'caption': { description: 'Texte de la légende du tableau', control: { type: 'text' }, }, 'showExpand': { description: 'Affiche une colonne permettant d\'étendre les lignes pour afficher du contenu supplémentaire', control: { type: 'boolean' }, table: { category: 'props', }, }, 'resizableColumns': { description: 'Permet de redimensionner les colonnes du tableau', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, }, }, 'multiSort': { description: 'Permet de trier sur plusieurs colonnes simultanément. Lorsque activé, des indicateurs numériques apparaissent à côté des icônes de tri pour montrer l\'ordre de priorité.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false', }, }, }, 'mustSort': { description: 'Force au moins une colonne à être toujours triée. Si désactivé, toutes les colonnes peuvent être non triées.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false', }, }, }, 'enableColumnControls': { description: 'Allow the users to re-organize the columns', table: { defaultValue: { summary: 'false', }, type: { summary: 'boolean' }, category: 'props', }, control: { type: 'boolean' }, }, 'showSelect': { description: 'Affiche des cases à cocher pour sélectionner des lignes', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, }, }, 'showSelectSingle': { description: 'Affiche des cases à cocher pour sélectionner une seule ligne à la fois', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, }, }, 'stickySelect': { description: 'Rend la colonne de sélection (cases à cocher) sticky à gauche quand showSelect ou showSelectSingle est activé.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false', }, }, }, 'pinnedColumns': { description: 'Liste des colonnes à épingler (sticky). Chaque entrée peut être une clé de colonne (string) ou un objet `{ key: string, side?: \'left\' | \'right\' }`. Par défaut, les colonnes sont épinglées à gauche.', control: { type: 'object' }, table: { category: 'props', type: { summary: 'Array' }, defaultValue: { summary: 'undefined' }, }, }, 'pinnedColumnKey': { description: 'Raccourci pour épingler une seule colonne à gauche. Équivalent à `pinnedColumns: [key]`. Ignoré si `pinnedColumns` est défini.', control: { type: 'text' }, table: { category: 'props', type: { summary: 'string' }, defaultValue: { summary: 'undefined' }, }, }, 'selectionKey': { description: 'Clé utilisée pour identifier chaque ligne lors de la sélection. Par défaut, utilise "id" si présent, sinon l\'objet complet.', control: { type: 'text' }, table: { category: 'props', type: { summary: 'string' }, defaultValue: { summary: 'undefined (fallback: id | objet complet)' }, }, }, 'clickableRow': { description: 'Rend chaque ligne cliquable. Quand cette prop est activée, la ligne devient focusable au clavier et émet `row-click` sur clic, `Entrée` ou `Espace`, sans interférer avec les éléments interactifs imbriqués.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, 'pageInput': { description: 'Affiche un champ de saisie numérique dans la pagination permettant de naviguer directement vers une page en la saisissant au clavier. La navigation est déclenchée à la validation (`Entrée`) ou à la perte de focus. La valeur est automatiquement clampée entre 1 et le nombre total de pages.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, 'hideDefaultFooter': { description: 'Masque le footer par défaut du tableau (pagination et contrôles de page). Utile lorsque l\'on souhaite gérer la pagination manuellement ou ne pas en afficher.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - 'cookie-description-${cookieName}' storybook can't infer dynamic slot name 'header.': { description: 'Slot permettant de personnaliser le rendu de l\'en-tête d\'une colonne spécifique. Remplacer `` par la clé de la colonne souhaitée.', control: undefined, table: { category: 'slots', type: { summary: 'slot', detail: `{ column: HeaderColumn, headers: HeaderColumn[][], columns: HeaderColumn[], locales: Record string)>, sortBy: DataOptions['sortBy'], someSelected: boolean, allSelected: boolean }`, }, }, }, 'onRow-click': { description: 'Émis lorsqu\'une ligne est activée alors que `clickableRow` est à `true`. Reçoit l\'objet de la ligne en paramètre. Les interactions avec des éléments déjà interactifs dans la ligne ne déclenchent pas cet événement.', table: { category: 'events', type: { summary: '(item: Record) => void' }, }, }, }, } satisfies Meta export default meta type Story = StoryObj export const Default: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'asc' }], page: 1, }, 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'caption': '', 'serverItemsLength': 15, 'suffix': 'server-default', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' }, { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' }, { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' }, { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' }, ] } // Initialize data fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: `
`, } }, } export const ServerSortBy: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'desc' }], page: 1, }, 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'caption': '', 'serverItemsLength': 15, 'suffix': 'server-sort', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' }, { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' }, { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' }, { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' }, ] } // Initialize data fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: `
`, } }, } export const ServerMultiSort: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, multiSort: true, sortBy: [ { key: 'lastname', order: 'desc', }, { key: 'firstname', order: 'asc', }, ], page: 1, }, 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'caption': '', 'suffix': 'server-sort', 'density': 'default', 'striped': false, 'multiSort': true, 'serverItemsLength': 7, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items.sort((a, b) => { for (const sort of sortBy) { const key = sort.key const r = String(a[key]).localeCompare(String(b[key])) const order = sort.order === 'asc' ? 1 : -1 if (r !== 0) { return r * order } } return 0 }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, { firstname: 'Agate', lastname: 'Beauchesne', email: 'agate.beauchesne@exemple.com', }, ] } // Initialize data fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: `

Cet exemple montre le tri multiple côté serveur avec des indicateurs d'ordre de priorité. Les chiffres à côté des icônes de tri indiquent l'ordre de priorité du tri.

`, } }, } export const ServerFilterByText: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'serverItemsLength': 15, 'headers': [ { title: 'Prénom', key: 'firstname', filterable: true, filterType: 'text', }, { title: 'Nom', key: 'lastname', filterable: true, filterType: 'text', }, { title: 'Email', key: 'email', filterable: true, filterType: 'text', }, ], 'caption': '', 'options': { itemsPerPage: 5, page: 1, filters: [], }, 'showFilters': true, 'suffix': 'server-filter-text', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render(args) { return { components: { SyServerTable }, setup() { const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const totalFilteredUsers = ref(0) const filteredUsers = ref[]>([]) const state = ref(StateEnum.IDLE) const fetchData = async (): Promise => { state.value = StateEnum.PENDING // Simulate API call await new Promise(resolve => setTimeout(resolve, 1000)) // Get all users let items = [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Martin', lastname: 'Lavoie', email: 'martin.lavoie@example.com' }, { firstname: 'Céline', lastname: 'Tremblay', email: 'celine.tremblay@example.com' }, { firstname: 'Jacques', lastname: 'Gagnon', email: 'jacques.gagnon@example.com' }, { firstname: 'Isabelle', lastname: 'Côté', email: 'isabelle.cote@example.com' }, { firstname: 'Philippe', lastname: 'Bouchard', email: 'philippe.bouchard@example.com' }, ] // Apply filters on server side if (options.value?.filters && options.value.filters.length > 0) { options.value.filters.forEach((filter) => { const { key, value } = filter items = items.filter((item) => { const itemValue = item[key] return String(itemValue).toLowerCase().includes(String(value).toLowerCase()) }) }) } const total = items.length // Apply pagination const { page = 1, itemsPerPage = 10 } = options.value || {} if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } filteredUsers.value = items as Record[] totalFilteredUsers.value = total state.value = StateEnum.RESOLVED } // Initialize data fetchData() return { args, filteredUsers, totalFilteredUsers, state, options, fetchData, StateEnum, } }, template: `
`, } }, } export const ServerFilterByNumber: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text', }, { title: 'Âge', key: 'age', filterable: true, filterType: 'number', }, { title: 'Salaire', key: 'salary', filterable: true, filterType: 'number', }, ], 'caption': '', 'options': { itemsPerPage: 5, page: 1, filters: [], }, 'serverItemsLength': 15, 'showFilters': true, 'suffix': 'server-filter-number', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render(args) { return { components: { SyServerTable }, setup() { const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const totalFilteredUsers = ref(0) const filteredUsers = ref[]>([]) const state = ref(StateEnum.IDLE) const fetchData = async (): Promise => { state.value = StateEnum.PENDING // Simulate API call await new Promise(resolve => setTimeout(resolve, 1000)) // Get all users let items = [ { name: 'Jean Dupont', age: 32, salary: 45000 }, { name: 'Marie Martin', age: 28, salary: 52000 }, { name: 'Pierre Durand', age: 45, salary: 65000 }, { name: 'Sophie Petit', age: 36, salary: 48000 }, { name: 'Thomas Leroy', age: 41, salary: 58000 }, { name: 'Julie Bernard', age: 29, salary: 47000 }, { name: 'Nicolas Moreau', age: 38, salary: 61000 }, { name: 'Camille Dubois', age: 33, salary: 49000 }, { name: 'Alexandre Lefebvre', age: 44, salary: 67000 }, { name: 'Émilie Girard', age: 31, salary: 51000 }, { name: 'Lucas Roux', age: 39, salary: 59000 }, { name: 'Chloé Lambert', age: 27, salary: 46000 }, { name: 'Maxime Simon', age: 42, salary: 63000 }, { name: 'Laura Fournier', age: 35, salary: 54000 }, { name: 'Antoine Mercier', age: 40, salary: 60000 }, ] // Apply filters on server side if (options.value?.filters && options.value.filters.length > 0) { options.value.filters.forEach((filter) => { const { key, value, type } = filter items = items.filter((item) => { const itemValue = item[key] if (type === 'number') { return Number(itemValue) === Number(value) } else { return String(itemValue).toLowerCase().includes(String(value).toLowerCase()) } }) }) } const total = items.length // Apply pagination const { page = 1, itemsPerPage = 10 } = options.value || {} if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } filteredUsers.value = items as Record[] totalFilteredUsers.value = total state.value = StateEnum.RESOLVED } // Initialize data fetchData() return { args, filteredUsers, totalFilteredUsers, options, state, fetchData, StateEnum, } }, template: `
`, } }, } export const ServerFilterBySelect: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text', }, { title: 'Département', key: 'department', filterable: true, filterType: 'select', multiple: false, chips: false, hideMessages: true, filterOptions: [ { text: 'RH', value: 'RH' }, { text: 'IT', value: 'IT' }, { text: 'Finance', value: 'Finance' }, { text: 'Marketing', value: 'Marketing' }, ], }, { title: 'Statut', key: 'status', filterable: true, filterType: 'select', multiple: false, chips: false, hideMessages: true, filterOptions: [ { text: 'Actif', value: 'Actif' }, { text: 'En congé', value: 'En congé' }, { text: 'Inactif', value: 'Inactif' }, ], }, ], 'caption': '', 'options': { itemsPerPage: 5, page: 1, filters: [], }, 'serverItemsLength': 15, 'showFilters': true, 'suffix': 'server-filter-select', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render(args) { return { components: { SyServerTable }, setup() { const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const totalFilteredUsers = ref(0) const filteredUsers = ref[]>([]) const state = ref(StateEnum.IDLE) const fetchData = async (): Promise => { state.value = StateEnum.PENDING // Simulate API call await new Promise(resolve => setTimeout(resolve, 1000)) // Get all users let items = [ { name: 'Jean Dupont', department: 'RH', status: 'Actif' }, { name: 'Marie Martin', department: 'IT', status: 'En congé' }, { name: 'Pierre Durand', department: 'Finance', status: 'Actif' }, { name: 'Sophie Petit', department: 'Marketing', status: 'Actif' }, { name: 'Thomas Leroy', department: 'IT', status: 'Inactif' }, { name: 'Julie Bernard', department: 'RH', status: 'Actif' }, { name: 'Nicolas Moreau', department: 'Finance', status: 'En congé' }, { name: 'Camille Dubois', department: 'Marketing', status: 'Inactif' }, { name: 'Alexandre Lefebvre', department: 'IT', status: 'Actif' }, { name: 'Émilie Girard', department: 'RH', status: 'En congé' }, { name: 'Lucas Roux', department: 'Finance', status: 'Actif' }, { name: 'Chloé Lambert', department: 'Marketing', status: 'Actif' }, { name: 'Maxime Simon', department: 'IT', status: 'Inactif' }, { name: 'Laura Fournier', department: 'RH', status: 'Actif' }, { name: 'Antoine Mercier', department: 'Finance', status: 'En congé' }, ] // Apply filters on server side if (options.value?.filters && options.value.filters.length > 0) { options.value.filters.forEach((filter) => { const { key, value, type } = filter items = items.filter((item) => { const itemValue = item[key] if (type === 'select') { return itemValue === value } else { return String(itemValue).toLowerCase().includes(String(value).toLowerCase()) } }) }) } const total = items.length // Apply pagination const { page = 1, itemsPerPage = 10 } = options.value || {} if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } filteredUsers.value = items as Record[] totalFilteredUsers.value = total state.value = StateEnum.RESOLVED } // Initialize data fetchData() return { args, filteredUsers, totalFilteredUsers, options, state, fetchData, StateEnum, } }, template: `
`, } }, } export const ServerFilterBySelectMultiple: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text', }, { title: 'Département', key: 'department', filterable: true, filterType: 'select', multiple: true, chips: true, hideMessages: true, filterOptions: [ { text: 'RH', value: 'RH' }, { text: 'IT', value: 'IT' }, { text: 'Finance', value: 'Finance' }, { text: 'Marketing', value: 'Marketing' }, ], }, { title: 'Statut', key: 'status', filterable: true, filterType: 'select', multiple: true, chips: true, hideMessages: true, filterOptions: [ { text: 'Actif', value: 'Actif' }, { text: 'En congé', value: 'En congé' }, { text: 'Inactif', value: 'Inactif' }, ], }, ], 'caption': '', 'options': { itemsPerPage: 5, page: 1, filters: [], }, 'serverItemsLength': 15, 'showFilters': true, 'suffix': 'server-filter-select', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render(args) { return { components: { SyServerTable }, setup() { const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const totalFilteredUsers = ref(0) const filteredUsers = ref[]>([]) const state = ref(StateEnum.IDLE) const fetchData = async (): Promise => { state.value = StateEnum.PENDING // Simulate API call await new Promise(resolve => setTimeout(resolve, 1000)) // Get all users let items = [ { name: 'Jean Dupont', department: 'RH', status: 'Actif' }, { name: 'Marie Martin', department: 'IT', status: 'En congé' }, { name: 'Pierre Durand', department: 'Finance', status: 'Actif' }, { name: 'Sophie Petit', department: 'Marketing', status: 'Actif' }, { name: 'Thomas Leroy', department: 'IT', status: 'Inactif' }, { name: 'Julie Bernard', department: 'RH', status: 'Actif' }, { name: 'Nicolas Moreau', department: 'Finance', status: 'En congé' }, { name: 'Camille Dubois', department: 'Marketing', status: 'Inactif' }, { name: 'Alexandre Lefebvre', department: 'IT', status: 'Actif' }, { name: 'Émilie Girard', department: 'RH', status: 'En congé' }, { name: 'Lucas Roux', department: 'Finance', status: 'Actif' }, { name: 'Chloé Lambert', department: 'Marketing', status: 'Actif' }, { name: 'Maxime Simon', department: 'IT', status: 'Inactif' }, { name: 'Laura Fournier', department: 'RH', status: 'Actif' }, { name: 'Antoine Mercier', department: 'Finance', status: 'En congé' }, ] // Apply filters on server side if (options.value?.filters && options.value.filters.length > 0) { options.value.filters.forEach((filter) => { const { key, value, type } = filter items = items.filter((item) => { const itemValue = item[key] if (type === 'select') { if (Array.isArray(value)) { // Empty array means no filter applied if (value.length === 0) return true // Check if item value is in the selected values return value.includes(itemValue) } else { return itemValue === value } } else { return String(itemValue).toLowerCase().includes(String(value).toLowerCase()) } }) }) } const total = items.length // Apply pagination const { page = 1, itemsPerPage = 10 } = options.value || {} if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } filteredUsers.value = items as Record[] totalFilteredUsers.value = total state.value = StateEnum.RESOLVED } // Initialize data fetchData() return { args, filteredUsers, totalFilteredUsers, options, state, fetchData, StateEnum, } }, template: `
`, } }, } export const ServerFilterByAutocomplete: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text' as FilterType, }, { title: 'Département', key: 'department', filterable: true, filterType: 'autocomplete' as FilterType, filterOptions: [ { text: 'RH', value: 'RH' }, { text: 'IT', value: 'IT' }, { text: 'Finance', value: 'Finance' }, { text: 'Marketing', value: 'Marketing' }, ], }, { title: 'Statut', key: 'status', filterable: true, filterType: 'autocomplete' as FilterType, multiple: true, chips: true, filterOptions: [ { text: 'Actif', value: 'Actif' }, { text: 'En congé', value: 'En congé' }, { text: 'Inactif', value: 'Inactif' }, ], }, ], 'serverItemsLength': 0, 'suffix': 'server-filter-autocomplete', 'showFilters': true, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const options = ref({ itemsPerPage: 5, page: 1, sortBy: [], filters: [], }) const filteredUsers = ref[]>([]) const totalFilteredUsers = ref(0) const state = ref(StateEnum.IDLE) const getUsers = () => [ { name: 'Jean Dupont', department: 'RH', status: 'Actif' }, { name: 'Marie Martin', department: 'IT', status: 'En congé' }, { name: 'Pierre Durand', department: 'Finance', status: 'Actif' }, { name: 'Sophie Petit', department: 'Marketing', status: 'Actif' }, { name: 'Thomas Leroy', department: 'IT', status: 'Inactif' }, ] const fetchData = async () => { state.value = StateEnum.PENDING await new Promise(resolve => setTimeout(resolve, 500)) let items = getUsers() if (options.value.filters?.length) { options.value.filters.forEach((filter) => { const { key, value, type } = filter items = items.filter((item) => { const itemValue = item[key as keyof typeof item] if (type === 'autocomplete') { if (Array.isArray(value)) { return value.length === 0 || value.includes(itemValue) } return itemValue === value } return String(itemValue).toLowerCase().includes(String(value).toLowerCase()) }) }) } totalFilteredUsers.value = items.length const { page = 1, itemsPerPage = 5 } = options.value filteredUsers.value = itemsPerPage > 0 ? items.slice((page - 1) * itemsPerPage, page * itemsPerPage) : items state.value = StateEnum.RESOLVED } fetchData() return { args, filteredUsers, totalFilteredUsers, options, state, fetchData, StateEnum, } }, template: `
`, } }, } export const ServerFilterByExacteDate: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'serverItemsLength': 5, 'showFilters': true, 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text', }, { title: 'Date d\'embauche', key: 'hireDate', filterable: true, filterType: 'date', dateFormat: 'DD/MM/YYYY', }, ], 'options': { itemsPerPage: 5, page: 1, filters: [], }, 'caption': '', 'suffix': 'server-filter-date', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render(args) { return { components: { SyServerTable }, setup() { // Original data that never changes const originalUsers = [ { name: 'Jean-Pierre Dubois', hireDate: dayjs('2025-05-15').format('DD/MM/YYYY'), }, { name: 'Marie-Claire Lefèvre', hireDate: dayjs('2025-03-10').format('DD/MM/YYYY'), }, { name: 'François Moreau', hireDate: dayjs('2025-11-22').format('DD/MM/YYYY'), }, { name: 'Céline Rousseau', hireDate: dayjs('2025-01-08').format('DD/MM/YYYY'), }, { name: 'Thierry Bertrand', hireDate: dayjs('2025-07-30').format('DD/MM/YYYY'), }, ] const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const totalUsers = ref(originalUsers.length) const users = ref([...originalUsers]) const state = ref(StateEnum.IDLE) const fetchData = async () => { state.value = StateEnum.PENDING // Simulate API delay await new Promise(resolve => setTimeout(resolve, 1000)) // Start with original data let filteredData = [...originalUsers] // Apply filters if any if (options.value.filters && options.value.filters.length > 0) { filteredData = filteredData.filter((user) => { return options.value.filters!.every((filter) => { const { key, value, type } = filter const itemValue = user[key as keyof typeof user] if (!value) return true if (type === 'date') { // Simple date comparison for demo purposes return itemValue === value } else if (type === 'period') { const filter = value as { from: string, to: string } const start = new Date(filter.from) const end = new Date(filter.to) const itemDate = new Date(itemValue) if (itemDate) { if (end && itemDate < end) { return false } if (start && itemDate > start) { return false } } return true } else { return String(itemValue).toLowerCase().includes(String(value).toLowerCase()) } }) }) } // Update the displayed data users.value = filteredData totalUsers.value = filteredData.length state.value = StateEnum.RESOLVED } // Initialize data fetchData() return { args, users, totalUsers, options, state, fetchData, StateEnum, } }, template: `
`, } }, } export const ServerFilterByPeriod: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'serverItemsLength': 5, 'showFilters': true, 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text', }, { title: 'Date d\'embauche', key: 'hireDate', filterable: true, filterType: 'period', dateFormat: 'DD/MM/YYYY', }, ], 'options': { itemsPerPage: 5, page: 1, filters: [], }, 'caption': '', 'suffix': 'server-filter-date', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render(args) { return { components: { SyServerTable }, setup() { // Original data that never changes const originalUsers = [ { name: 'Jean-Pierre Dubois', hireDate: dayjs('2025-05-15').format('DD/MM/YYYY'), }, { name: 'Marie-Claire Lefèvre', hireDate: dayjs('2025-03-10').format('DD/MM/YYYY'), }, { name: 'François Moreau', hireDate: dayjs('2025-11-22').format('DD/MM/YYYY'), }, { name: 'Céline Rousseau', hireDate: dayjs('2025-01-08').format('DD/MM/YYYY'), }, { name: 'Thierry Bertrand', hireDate: dayjs('2025-07-30').format('DD/MM/YYYY'), }, ] const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const totalUsers = ref(originalUsers.length) const users = ref([...originalUsers]) const state = ref(StateEnum.IDLE) const fetchData = async () => { state.value = StateEnum.PENDING // Simulate API delay await new Promise(resolve => setTimeout(resolve, 1000)) // Start with original data let filteredData = [...originalUsers] // Apply filters if any if (options.value.filters && options.value.filters.length > 0) { filteredData = filteredData.filter((user) => { return options.value.filters!.every((filter) => { const { key, value, type } = filter const itemValue = user[key as keyof typeof user] if (!value) return true else if (type === 'period') { const formatDate = (date: string): Date | null => { if (!date) return null const parsedDate = dayjs(date, 'DD/MM/YYYY') return parsedDate.isValid() ? parsedDate.toDate() : null } const filter = value as { from: string, to: string } const start = formatDate(filter.from) const end = formatDate(filter.to) const itemDate = formatDate(itemValue) if (itemDate) { if (end && itemDate > end) { return false } if (start && itemDate < start) { return false } } return true } else { return String(itemValue).toLowerCase().includes(String(value).toLowerCase()) } }) }) } // Update the displayed data users.value = filteredData totalUsers.value = filteredData.length state.value = StateEnum.RESOLVED } // Initialize data fetchData() return { args, users, totalUsers, options, state, fetchData, StateEnum, } }, template: `
`, } }, } export const CustomFilterSlot: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, { name: 'Style', code: ` `, }, ], }, args: { 'serverItemsLength': 6, 'headers': [ { title: 'Nom', key: 'lastname', filterable: true, filterType: 'text', }, { title: 'Prénom', key: 'firstname', filterable: true, filterType: 'text', }, { title: 'Statut', key: 'status', filterable: true, filterType: 'custom' as FilterType, }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', status: 'Actif', }, { firstname: 'Simone', lastname: 'Bellefeuille', status: 'Inactif', }, { firstname: 'Étienne', lastname: 'Salois', status: 'En attente', }, { firstname: 'Thierry', lastname: 'Bobu', status: 'Actif', }, { firstname: 'Bernadette', lastname: 'Langelier', status: 'Inactif', }, { firstname: 'Agate', lastname: 'Roy', status: 'En attente', }, ], 'caption': '', 'options': { itemsPerPage: 4, page: 1, filters: [], }, 'showFilters': true, 'suffix': 'server-custom-filter-slot', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render(args) { return { components: { SyServerTable }, setup() { // Create reactive references const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const items = ref(args.items) const customFilterValue = ref('') const statusOptions = ['Actif', 'Inactif', 'En attente'] const loading = ref(false) const serverItemsLength = ref(args.serverItemsLength) // Fonction pour simuler une requête API avec filtrage côté serveur const fetchData = async () => { loading.value = true // Simuler un délai réseau await new Promise(resolve => setTimeout(resolve, 300)) // Récupérer les filtres const filters = options.value?.filters || [] // Filtrer les éléments côté "serveur" let filteredItems = [...(args.items || [])] for (const filter of filters) { if (filter.type === 'text') { filteredItems = filteredItems.filter(item => String(item[filter.key]).toLowerCase().includes(String(filter.value).toLowerCase()), ) } else if (filter.type === 'select' || filter.type === 'custom') { // Traiter les filtres de type 'select' et 'custom' de la même manière filteredItems = filteredItems.filter(item => item[filter.key] === filter.value, ) } } // Mettre à jour le nombre total d'éléments serverItemsLength.value = filteredItems.length // Appliquer la pagination const page = options.value?.page || 1 const itemsPerPage = options.value?.itemsPerPage || 4 const start = (page - 1) * itemsPerPage const end = start + itemsPerPage items.value = filteredItems.slice(start, end) loading.value = false } function handleFilterChange(val) { // Ensure options.value.filters is initialized if (!options.value.filters) { options.value.filters = [] } // Create a new filters array with proper typing const currentFilters = options.value.filters as import('../common/types').FilterOption[] const newFilters = [...currentFilters].filter(f => f.key !== 'status') // Add the new filter if a value is selected if (val) { newFilters.push({ key: 'status', value: val, type: 'select' as FilterType, // Use 'select' type for compatibility with filtering logic }) } // Update the options with the new filters options.value = { ...options.value, filters: newFilters, } } // Initialize data fetchData() return { args, options, items, customFilterValue, statusOptions, loading, serverItemsLength, handleFilterChange, fetchData, } }, template: ` `, } }, } export const CustomFilterInputs: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'serverItemsLength': 15, 'headers': [ { title: 'Prénom', key: 'firstname', filterable: true, filterType: 'text', }, { title: 'Nom', key: 'lastname', filterable: true, filterType: 'text', }, { title: 'Email', key: 'email', filterable: true, filterType: 'text', }, ], 'caption': '', 'options': { itemsPerPage: 5, page: 1, filters: [], }, 'filterInputConfig': { variant: 'outlined', density: 'comfortable', hideDetails: true, clearable: false, disableErrorHandling: true, }, 'showFilters': true, 'suffix': 'server-filter-text', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render(args) { return { components: { SyServerTable }, setup() { const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const totalFilteredUsers = ref(0) const filteredUsers = ref[]>([]) const state = ref(StateEnum.IDLE) const fetchData = async (): Promise => { state.value = StateEnum.PENDING // Simulate API call await new Promise(resolve => setTimeout(resolve, 1000)) // Get all users let items = [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Martin', lastname: 'Lavoie', email: 'martin.lavoie@example.com' }, { firstname: 'Céline', lastname: 'Tremblay', email: 'celine.tremblay@example.com' }, { firstname: 'Jacques', lastname: 'Gagnon', email: 'jacques.gagnon@example.com' }, { firstname: 'Isabelle', lastname: 'Côté', email: 'isabelle.cote@example.com' }, { firstname: 'Philippe', lastname: 'Bouchard', email: 'philippe.bouchard@example.com' }, ] // Apply filters on server side if (options.value?.filters && options.value.filters.length > 0) { options.value.filters.forEach((filter) => { const { key, value } = filter items = items.filter((item) => { const itemValue = item[key] return String(itemValue).toLowerCase().includes(String(value).toLowerCase()) }) }) } const total = items.length // Apply pagination const { page = 1, itemsPerPage = 10 } = options.value || {} if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } filteredUsers.value = items as Record[] totalFilteredUsers.value = total state.value = StateEnum.RESOLVED } // Initialize data fetchData() return { args, filteredUsers, totalFilteredUsers, options, state, fetchData, StateEnum, } }, template: `
`, } }, } export const ManyServerTables: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'serverItemsLength': 15, // Add required serverItemsLength property 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'caption': '', 'suffix': 'multi', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { // Table 1 const totalUsersTable1 = ref(0) const usersTable1 = ref([]) const stateTable1 = ref(StateEnum.IDLE) const optionsTable1 = ref>({ itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'asc' }], page: 1, }) const fetchDataTable1 = async (options?: DataOptions): Promise => { const optionsToUse = options || optionsTable1.value as DataOptions const { items, total } = await getDataFromApi(optionsToUse) usersTable1.value = items totalUsersTable1.value = total } // Table 2 const totalUsersTable2 = ref(0) const usersTable2 = ref([]) const stateTable2 = ref(StateEnum.IDLE) const optionsTable2 = ref>({ itemsPerPage: 3, sortBy: [{ key: 'firstname', order: 'asc' }], page: 1, }) const fetchDataTable2 = async (options?: DataOptions): Promise => { const optionsToUse = options || optionsTable2.value as DataOptions const { items, total } = await getDataFromApi(optionsToUse) usersTable2.value = items totalUsersTable2.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise => { const state = sortBy[0]!.key === 'lastname' ? stateTable1 : stateTable2 state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, ] } // Chargement initial des données fetchDataTable1() fetchDataTable2() return { args, usersTable1, totalUsersTable1, optionsTable1, stateTable1, fetchDataTable1, usersTable2, totalUsersTable2, optionsTable2, stateTable2, fetchDataTable2, StateEnum, } }, template: `
`, } }, } export const DataAlignment: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'asc' }], page: 1, }, 'headers': [ { title: 'ID', key: 'id', align: 'center', }, { title: 'Nom', key: 'lastname', align: 'start', }, { title: 'Date de naissance', key: 'birthdate', align: 'center', }, { title: 'NIR', key: 'nir', align: 'end', }, ], 'caption': '', 'serverItemsLength': 3, 'suffix': 'server-resizable-columns', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { // @ts-expect-error - fetchData is not defined const { items, total } = await getDataFromApi(options.value) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions) => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = () => { return [ { id: '1', lastname: 'Lefebvre', birthdate: '18/02/1989', nir: '1 89 02 75 120 005 79', }, { id: '2', lastname: 'Richard', birthdate: '22/05/1991', nir: '2 91 05 75 120 005 76', }, { id: '3', lastname: 'Fournier', birthdate: '11/11/2000', nir: '2 00 11 42 120 008 87', }, ] } fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: ` `, } }, } export const ResizableColumns: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'asc' }], page: 1, }, 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'caption': '', 'serverItemsLength': 15, 'suffix': 'server-resizable-columns', 'density': 'default', 'striped': false, 'resizableColumns': true, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' }, { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' }, { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' }, { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' }, ] } fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: `
`, } }, } export const ClickableRow: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Alice', lastname: 'Dupont', email: 'alice.dupont@example.com' }, { firstname: 'Marc', lastname: 'Lefevre', email: 'marc.lefevre@example.com' }, ], 'serverItemsLength': 4, 'options': { itemsPerPage: 5, filters: [] }, 'clickableRow': true, 'suffix': 'clickable-row-server-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), 'onRow-click': fn(), }, render: (args) => { return { components: { ClickableRowServerTableCanvas: defineComponent({ components: { SyServerTable }, emits: ['row-click'], setup() { const options = ref({ itemsPerPage: 5, page: 1, sortBy: [], filters: [], ...(args.options ?? {}), }) const state = ref(StateEnum.IDLE) const totalUsers = ref(0) const users = ref[]>([]) const allUsers = [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Alice', lastname: 'Dupont', email: 'alice.dupont@example.com' }, { firstname: 'Marc', lastname: 'Lefevre', email: 'marc.lefevre@example.com' }, ] const boundArgs = computed(() => { return Object.fromEntries( Object.entries(args).filter(([key]) => !['items', 'options', 'serverItemsLength', 'onRow-click'].includes(key)), ) }) const fetchData = async (nextOptions?: DataOptions) => { if (nextOptions) { options.value = { ...options.value, ...nextOptions } } state.value = StateEnum.PENDING await new Promise(resolve => setTimeout(resolve, 500)) const items = [...allUsers] const { page = 1, itemsPerPage = 5, sortBy = [] } = options.value if (sortBy.length > 0) { const [firstSort] = sortBy if (firstSort?.key && firstSort.order) { items.sort((a, b) => { const left = String(a[firstSort.key] ?? '') const right = String(b[firstSort.key] ?? '') return firstSort.order === 'asc' ? left.localeCompare(right) : right.localeCompare(left) }) } } totalUsers.value = items.length users.value = itemsPerPage > 0 ? items.slice((page - 1) * itemsPerPage, page * itemsPerPage) : items state.value = StateEnum.RESOLVED } fetchData() return { boundArgs, fetchData, options, state, totalUsers, users, StateEnum } }, template: ` `, }), }, setup() { const selectedRow = ref | null>(null) const handleRowClick = (item: Record) => { selectedRow.value = item args['onRow-click']?.(item) } return { selectedRow, handleRowClick } }, template: `

Ligne cliquée

Nom: {{ selectedRow.lastname }}
Prénom: {{ selectedRow.firstname }}
Email: {{ selectedRow.email }}
`, } }, } export const RowSelection: Story = { name: 'Row Selection', parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname', }, { title: 'Prénom', key: 'firstname', }, { title: 'Email', value: 'email', }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, ], 'options': { itemsPerPage: 4, page: 1, filters: [], }, 'caption': '', 'suffix': 'selection-server-table', 'density': 'default', 'striped': false, 'showSelect': true, 'showFilters': true, 'serverItemsLength': 6, 'onUpdate:options': fn(), }, render(args) { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const selection = ref([]) const state = ref(StateEnum.IDLE) const fetchData = async (): Promise => { // Create a complete DataOptions object with all required properties const defaultOptions: DataOptions = { page: 1, itemsPerPage: 10, sortBy: [], multiSort: false, } const options = args.options ? { ...defaultOptions, ...args.options } : defaultOptions const { items, total } = await getDataFromApi(options) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() let total = items.length // Changed from const to let // Add filtering logic here if (filters && filters.length > 0) { filters.forEach((filter) => { const { key, value } = filter items = items.filter((item) => { const itemValue = item[key] return String(itemValue).toLowerCase().includes(String(value).toLowerCase()) }) }) // Update total after filtering total = items.length } if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, ] } // Keep a full copy of all users for selection display across pages const allUsers = ref(getUsers()) // Call fetchData on mount fetchData() return { args, users, allUsers, state, fetchData, totalUsers, selection, StateEnum } }, template: `

Item(s) sélectionné(s) ({{ selection.length }})

Nom: {{ typeof item === 'object' ? item.lastname : allUsers.find(i => JSON.stringify(i) === item)?.lastname }}
Prénom: {{ typeof item === 'object' ? item.firstname : allUsers.find(i => JSON.stringify(i) === item)?.firstname }}
Email: {{ typeof item === 'object' ? item.email : allUsers.find(i => JSON.stringify(i) === item)?.email }}
`, } }, } export const SingleRowSelection: Story = { name: 'Single Row Selection', parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname', }, { title: 'Prénom', key: 'firstname', }, { title: 'Email', value: 'email', }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, ], 'options': { itemsPerPage: 4, page: 1, filters: [], }, 'caption': '', 'suffix': 'selection-server-table', 'density': 'default', 'striped': false, 'showSelectSingle': true, 'showFilters': true, 'serverItemsLength': 6, 'onUpdate:options': fn(), }, render(args) { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const selection = ref([]) const state = ref(StateEnum.IDLE) const fetchData = async (): Promise => { // Create a complete DataOptions object with all required properties const defaultOptions: DataOptions = { page: 1, itemsPerPage: 10, sortBy: [], multiSort: false, } const options = args.options ? { ...defaultOptions, ...args.options } : defaultOptions const { items, total } = await getDataFromApi(options) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage, filters }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() let total = items.length // Changed from const to let // Add filtering logic here if (filters && filters.length > 0) { filters.forEach((filter) => { const { key, value } = filter items = items.filter((item) => { const itemValue = item[key] return String(itemValue).toLowerCase().includes(String(value).toLowerCase()) }) }) // Update total after filtering total = items.length } if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, ] } // Keep a full copy of all users for selection display across pages const allUsers = ref(getUsers()) // Call fetchData on mount fetchData() return { args, users, allUsers, state, fetchData, totalUsers, selection, StateEnum } }, template: `

Item(s) sélectionné(s) ({{ selection.length }})

Nom: {{ typeof item === 'object' ? item.lastname : allUsers.find(i => JSON.stringify(i) === item)?.lastname }}
Prénom: {{ typeof item === 'object' ? item.firstname : allUsers.find(i => JSON.stringify(i) === item)?.firstname }}
Email: {{ typeof item === 'object' ? item.email : allUsers.find(i => JSON.stringify(i) === item)?.email }}
`, } }, } export const PinnedColumns: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, page: 1, }, 'headers': [ { title: 'ID', key: 'id', width: 80 }, { title: 'Nom', key: 'lastname', width: 160 }, { title: 'Prénom', key: 'firstname', width: 160 }, { title: 'Email', key: 'email', width: 240 }, { title: 'Ville', key: 'city', width: 160 }, { title: 'Pays', key: 'country', width: 160 }, { title: 'Téléphone', key: 'phone', width: 180 }, { title: 'Statut', key: 'status', width: 140 }, { title: 'Dernière connexion', key: 'lastLogin', width: 200 }, { title: 'Actions', key: 'actions', width: 140 }, ], 'serverItemsLength': 30, 'suffix': 'server-pinned-columns', 'showSelect': true, 'stickySelect': true, 'pinnedColumns': [ { key: 'actions', side: 'right' }, ], 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const argsWithoutOptions = Object.fromEntries( Object.entries(args as Record).filter(([k]) => k !== 'options'), ) const users = ref[]>([]) const totalUsers = ref(args.serverItemsLength) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options } as DataOptions) const getUsers = (): Record[] => { return Array.from({ length: 30 }).map((_, i) => ({ id: i + 1, lastname: 'Nom ' + (i + 1), firstname: 'Prénom ' + (i + 1), email: 'user' + (i + 1) + '@example.com', city: 'Paris', country: 'France', phone: '01 02 03 04 05', status: i % 2 === 0 ? 'Actif' : 'Inactif', lastLogin: dayjs().subtract(i, 'day').format('DD/MM/YYYY'), actions: '…', })) } const fetchData = async (): Promise => { state.value = StateEnum.PENDING await new Promise(resolve => setTimeout(resolve, 1000)) const all = getUsers() const start = ((options.value.page ?? 1) - 1) * (options.value.itemsPerPage ?? 5) const end = start + (options.value.itemsPerPage ?? 5) users.value = all.slice(start, end) totalUsers.value = all.length state.value = StateEnum.RESOLVED } watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } fetchData() }, { deep: true, immediate: true }) return { args: argsWithoutOptions, users, totalUsers, state, options, fetchData, StateEnum } }, template: `
`, } }, } export const ColumnControls: StoryObj = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'asc' }], page: 1, }, 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'caption': '', 'serverItemsLength': 15, 'suffix': 'server-control-columns', 'density': 'default', 'striped': false, 'enableColumnControls': true, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' }, { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' }, { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' }, { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' }, ] } fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: `
`, } }, } export const ExpandableRows: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'asc' }], page: 1, }, 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'caption': '', 'serverItemsLength': 15, 'showExpand': true, 'suffix': 'server-expandable', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' }, { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' }, { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' }, { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' }, ] } // Initialize data fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum, mdiChevronDown, mdiChevronUp } }, template: `
`, } }, } export const SlotItem: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'asc' }], page: 1, }, 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'caption': '', 'serverItemsLength': 15, 'suffix': 'server-default', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' }, { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' }, { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' }, { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' }, ] } // Initialize data fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: `
`, } }, } export const SlotHeaders: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'asc' }], page: 1, }, 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'caption': '', 'serverItemsLength': 15, 'suffix': 'server-default', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' }, { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' }, { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' }, { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' }, ] } // Initialize data fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: `
`, } }, } export const SlotHeader: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'asc' }], page: 1, }, 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'caption': '', 'serverItemsLength': 15, 'suffix': 'server-default', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' }, { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' }, { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' }, { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' }, ] } // Initialize data fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: `
`, } }, } export const ItemsPerPageOptions: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'asc' }], page: 1, }, 'itemsPerPageOptions': [5, 10, 15], 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'caption': '', 'serverItemsLength': 15, 'suffix': 'server-default', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items: User[] = getUsers() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key]! > b[key]! ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => { return [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, { firstname: 'Jacques', lastname: 'Demers', email: 'jacques.demers@example.com' }, { firstname: 'Aimée', lastname: 'Josseaume', email: 'aimee.josseaume@example.com' }, { firstname: 'Delphine', lastname: 'Robillard', email: 'delphine.robillard@example.com' }, { firstname: 'Alexandre', lastname: 'Lazure', email: 'alexandre.lazure@example.com' }, ] } // Initialize data fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: `
`, } }, } export const ComplexItemsDisplay: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, sortBy: [{ key: 'title', order: 'asc' }], page: 1, }, 'headers': [ { title: 'Titre', key: 'title' }, { title: 'Période', key: 'period' }, { title: 'Statut', key: 'status' }, ], 'caption': '', 'serverItemsLength': 6, 'suffix': 'server-default', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { type Item = { title: string period: { start: string end: string } status: string } const totalItems = ref(0) const items = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items: fetchedItems, total } = await getDataFromApi(options.value as DataOptions) items.value = fetchedItems totalItems.value = total } const wait = async (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise<{ items: Item[], total: number }> => { state.value = StateEnum.PENDING await wait(1000) return new Promise((resolve) => { let items = getItems() const total = items.length if (sortBy && sortBy.length > 0) { items = items.sort((a, b) => { const key = sortBy[0]!.key const order = sortBy[0]!.order === 'asc' ? 1 : -1 return a[key] > b[key] ? order : -order }) } if (itemsPerPage > 0) { items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage) } resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getItems = () => { return [ { title: 'Projet Alpha', period: { start: '2023-01-01', end: '2023-06-30' }, status: 'En cours' }, { title: 'Projet Beta', period: { start: '2022-05-15', end: '2022-12-15' }, status: 'Terminé' }, { title: 'Projet Gamma', period: { start: '2023-03-01', end: '2023-09-30' }, status: 'En cours' }, { title: 'Projet Delta', period: { start: '2021-11-01', end: '2022-04-30' }, status: 'Terminé' }, { title: 'Projet Epsilon', period: { start: '2023-07-01', end: '2023-12-31' }, status: 'À venir' }, { title: 'Projet Zeta', period: { start: '2022-02-01', end: '2022-08-31' }, status: 'Terminé' }, ] } // Initialize data fetchData() return { args, items, state, fetchData, options, totalItems, StateEnum } }, template: `
`, } }, } export const HideDefaultFooter: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: -1, page: 1 }, 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'serverItemsLength': 6, 'suffix': 'server-hide-footer', 'density': 'default', 'striped': false, 'hideDefaultFooter': true, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const getDataFromApi = async ({ page, itemsPerPage }: DataOptions): Promise<{ items: User[], total: number }> => { state.value = StateEnum.PENDING await new Promise(resolve => setTimeout(resolve, 500)) return new Promise((resolve) => { const allItems = getUsers() const total = allItems.length const items = itemsPerPage > 0 ? allItems.slice((page - 1) * itemsPerPage, page * itemsPerPage) : allItems resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, ] fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: `
`, } }, } export const PageInput: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'options': { itemsPerPage: 5, page: 1 }, 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'serverItemsLength': 11, 'suffix': 'server-page-input', 'density': 'default', 'striped': false, 'pageInput': true, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyServerTable }, setup() { const totalUsers = ref(0) const users = ref([]) const state = ref(StateEnum.IDLE) const options = ref({ ...args.options }) watch(options, (newVal) => { if (args.options) { Object.assign(args.options, JSON.parse(JSON.stringify(newVal))) } }, { deep: true }) const fetchData = async (): Promise => { const { items, total } = await getDataFromApi(options.value as DataOptions) users.value = items totalUsers.value = total } const getDataFromApi = async ({ page, itemsPerPage }: DataOptions): Promise<{ items: User[], total: number }> => { state.value = StateEnum.PENDING await new Promise(resolve => setTimeout(resolve, 500)) return new Promise((resolve) => { const allItems = getUsers() const total = allItems.length const items = itemsPerPage > 0 ? allItems.slice((page - 1) * itemsPerPage, page * itemsPerPage) : allItems resolve({ items, total }) state.value = StateEnum.RESOLVED }) } const getUsers = (): User[] => [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@example.com' }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@example.com' }, { firstname: 'Louis', lastname: 'Denis', email: 'louis.denis@example.com' }, { firstname: 'Édith', lastname: 'Cartier', email: 'edith.cartier@example.com' }, { firstname: 'Alphonse', lastname: 'Bouvier', email: 'alphonse.bouvier@example.com' }, { firstname: 'Eustache', lastname: 'Dubois', email: 'eustache.dubois@example.com' }, { firstname: 'Rosemarie', lastname: 'Quessy', email: 'rosemarie.quessy@example.com' }, { firstname: 'Serge', lastname: 'Rivard', email: 'serge.rivard@example.com' }, ] fetchData() return { args, users, state, fetchData, options, totalUsers, StateEnum } }, template: `
`, } }, }