import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { fn } from 'storybook/test'
import { ref } from 'vue'
import SyTable from './SyTable.vue'
import { commonTableArgTypes } from '../common/storyArgTypes'
import type { DataOptions, FilterType } from '../common/types'
import type { VDataTable } from 'vuetify/components'
import dayjs from 'dayjs'
const meta = {
title: 'Composants/Tableaux/SyTable/Filtres',
component: SyTable,
decorators: [
() => ({
template: '
',
}),
],
parameters: {
layout: 'fullscreen',
},
argTypes: {
...commonTableArgTypes,
items: {
description: 'Liste des éléments à afficher dans le tableau',
control: { type: 'object' },
table: {
category: 'props',
defaultValue: {
summary: '[]',
},
},
},
showFilters: {
description: 'Affiche les filtres au-dessus du tableau',
control: { type: 'boolean' },
},
},
} satisfies Meta
export default meta
type Story = StoryObj
export const FilterByText: Story = {
parameters: {
a11y: {
disable: true,
},
sourceCode: [
{
name: 'Template',
code: `
`,
},
{
name: 'Script',
code: `
`,
},
],
},
args: {
'headers': [
{
title: 'Nom',
key: 'lastname',
filterable: true,
filterType: 'text',
},
{
title: 'Prénom',
key: 'firstname',
filterable: true,
filterType: 'text',
},
{
title: 'Email',
value: 'email',
filterable: true,
filterType: 'text',
},
],
'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',
},
],
'caption': '',
'options': {
itemsPerPage: 4,
filters: [],
},
'showFilters': true,
'suffix': 'filter-text-table',
'density': 'default',
'striped': false,
'onUpdate:options': fn(),
},
render: (args) => {
return {
components: { SyTable },
setup() {
// Create reactive references
const options = ref(args.options)
const items = ref(args.items)
return {
args,
options,
items,
}
},
template: `
`,
}
},
}
export const FilterByNumber: 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',
},
],
'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,
},
],
'caption': '',
'options': {
itemsPerPage: 5,
filters: [],
},
'showFilters': true,
'suffix': 'filter-number-table',
'density': 'default',
'striped': false,
'onUpdate:options': fn(),
},
render: (args) => {
return {
components: { SyTable },
setup() {
// Create reactive references
const options = ref(args.options)
const items = ref(args.items)
return {
args,
options,
items,
}
},
template: `
`,
}
},
}
export const FilterBySelect: 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' },
],
},
],
'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',
},
],
'caption': '',
'options': {
itemsPerPage: 5,
filters: [],
},
'showFilters': true,
'suffix': 'filter-select-table',
'density': 'default',
'striped': false,
'onUpdate:options': fn(),
},
render: (args) => {
return {
components: { SyTable },
setup() {
// Create reactive references
const options = ref(args.options)
const items = ref(args.items)
return {
args,
options,
items,
}
},
template: `
`,
}
},
}
export const FilterBySelectMultiple: 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' },
],
},
],
'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',
},
],
'caption': '',
'options': {
itemsPerPage: 5,
filters: [],
},
'showFilters': true,
'suffix': 'filter-select-table',
'density': 'default',
'striped': false,
'onUpdate:options': fn(),
},
render: (args) => {
return {
components: { SyTable },
setup() {
// Create reactive references
const options = ref(args.options)
const items = ref(args.items)
return {
args,
options,
items,
}
},
template: `
`,
}
},
}
export const FilterByAutocomplete: 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: 'autocomplete',
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',
multiple: true,
chips: true,
filterOptions: [
{ text: 'Actif', value: 'Actif' },
{ text: 'En congé', value: 'En congé' },
{ text: 'Inactif', value: 'Inactif' },
],
},
],
'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' },
],
'caption': '',
'options': {
itemsPerPage: 5,
filters: [],
},
'showFilters': true,
'suffix': 'filter-autocomplete-table',
'density': 'default',
'striped': false,
'onUpdate:options': fn(),
},
render: (args) => {
return {
components: { SyTable },
setup() {
const options = ref(args.options)
const items = ref(args.items)
return {
args,
options,
items,
}
},
template: `
`,
}
},
}
export const FilterByExactDate: Story = {
parameters: {
a11y: {
disable: true,
},
sourceCode: [
{
name: 'Template',
code: `
`,
},
{
name: 'Script',
code: `
`,
},
],
},
args: {
'headers': [
{
title: 'Nom',
key: 'name',
filterable: true,
filterType: 'text',
},
{
title: 'Date d\'embauche',
key: 'hireDate',
filterable: true,
filterType: 'date',
dateFormat: 'DD/MM/YYYY',
},
],
'items': [
{
name: 'Jean Dupont',
hireDate: dayjs('2025-05-15').format('DD/MM/YYYY'),
},
{
name: 'Marie Martin',
hireDate: dayjs('2025-03-10').format('DD/MM/YYYY'),
},
{
name: 'Pierre Durand',
hireDate: dayjs('2025-11-22').format('DD/MM/YYYY'),
},
{
name: 'Sophie Petit',
hireDate: dayjs('2025-01-08').format('DD/MM/YYYY'),
},
{
name: 'Thomas Leroy',
hireDate: dayjs('2025-07-30').format('DD/MM/YYYY'),
},
],
'caption': '',
'options': {
itemsPerPage: 5,
filters: [],
},
'showFilters': true,
'suffix': 'filter-date-table',
'density': 'default',
'striped': false,
'onUpdate:options': fn(),
},
render: (args) => {
return {
components: { SyTable },
setup() {
// Create reactive references
const options = ref(args.options)
const items = ref(args.items)
return {
args,
options,
items,
}
},
template: `
`,
}
},
}
export const FilterByPeriod: Story = {
parameters: {
a11y: {
disable: true,
},
sourceCode: [
{
name: 'Template',
code: `
`,
},
{
name: 'Script',
code: `
`,
},
],
},
args: {
'headers': [
{
title: 'Nom',
key: 'name',
filterable: true,
filterType: 'text',
},
{
title: 'Date d\'embauche',
key: 'hireDate',
filterable: true,
filterType: 'period',
dateFormat: 'DD/MM/YYYY',
},
],
'items': [
{
name: 'Jean Dupont',
hireDate: dayjs('2025-05-15').format('DD/MM/YYYY'),
},
{
name: 'Marie Martin',
hireDate: dayjs('2025-03-10').format('DD/MM/YYYY'),
},
{
name: 'Pierre Durand',
hireDate: dayjs('2025-11-22').format('DD/MM/YYYY'),
},
{
name: 'Sophie Petit',
hireDate: dayjs('2025-01-08').format('DD/MM/YYYY'),
},
{
name: 'Thomas Leroy',
hireDate: dayjs('2025-07-30').format('DD/MM/YYYY'),
},
],
'caption': '',
'options': {
itemsPerPage: 5,
filters: [],
},
'showFilters': true,
'suffix': 'filter-date-table',
'density': 'default',
'striped': false,
'onUpdate:options': fn(),
},
render: (args) => {
return {
components: { SyTable },
setup() {
// Create reactive references
const options = ref(args.options)
const items = ref(args.items)
return {
args,
options,
items,
}
},
template: `
`,
}
},
}
export const CustomFilterSlot: Story = {
parameters: {
a11y: {
disable: true,
},
docs: {
description: {
story: 'Cette story démontre comment utiliser un slot personnalisé pour le filtrage. Le filtre personnalisé utilise un v-select pour filtrer par statut.',
},
},
sourceCode: [
{
name: 'Template',
code: `
Filtre personnalisé :
{
// Use updateFilter provided by the slot props
updateFilter(val);
// Also update our local state
handleFilterChange(val);
}"
/>
`,
},
{
name: 'Script',
code: `
`,
},
{
name: 'Style',
code: `
`,
},
],
},
args: {
'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',
},
],
'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,
filters: [],
},
'showFilters': true,
'suffix': 'custom-filter-slot-table',
'density': 'default',
'striped': false,
'onUpdate:options': fn(),
},
render: (args) => {
return {
components: { SyTable },
setup() {
// Create a fresh copy of the options to avoid reactivity issues
const options = ref({
page: 1,
itemsPerPage: 4,
filters: [] as import('../common/types').FilterOption[],
sortBy: [],
})
// Create a reactive reference for the custom filter value
const customFilterValue = ref('')
const statusOptions = ['Actif', 'Inactif', 'En attente']
// Function to update the filter when the select value changes
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,
}
}
return {
args,
options,
customFilterValue,
statusOptions,
handleFilterChange,
}
},
template: `
Filtre personnalisé :
{
// Use updateFilter provided by the slot props
updateFilter(val);
// Also update our local state
handleFilterChange(val);
}"
/>
`,
}
},
}
export const CustomFilterInputs: Story = {
parameters: {
a11y: {
disable: true,
},
sourceCode: [
{
name: 'Template',
code: `
`,
},
{
name: 'Script',
code: `
`,
},
],
},
args: {
'headers': [
{
title: 'Nom',
key: 'lastname',
filterable: true,
filterType: 'text',
},
{
title: 'Prénom',
key: 'firstname',
filterable: true,
filterType: 'text',
},
{
title: 'Email',
value: 'email',
filterable: true,
filterType: 'text',
},
],
'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',
},
],
'caption': '',
'options': {
itemsPerPage: 4,
filters: [],
},
'filterInputConfig': {
variant: 'outlined',
density: 'comfortable',
hideDetails: true,
clearable: false,
disableErrorHandling: true,
},
'showFilters': true,
'suffix': 'filter-text-table',
'density': 'default',
'striped': false,
'onUpdate:options': fn(),
},
render: (args) => {
return {
components: { SyTable },
setup() {
// Create reactive references
const options = ref(args.options)
const items = ref(args.items)
return {
args,
options,
items,
}
},
template: `
`,
}
},
}