Skip to content

Commit 37c7c85

Browse files
authored
Merge pull request #586 from dnum-mi/develop
Develop
2 parents fdce331 + 990977f commit 37c7c85

File tree

3 files changed

+272
-11
lines changed

3 files changed

+272
-11
lines changed

src/components/DsfrSelect/DsfrSelect.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const props = withDefaults(defineProps<{
1313
description?: string
1414
modelValue?: string | number
1515
label?: string
16-
options?:(string | number | { value: string | number, text: string, disabled: boolean })[]
16+
options?:(string | number | { value: string | number, text: string, disabled?: boolean })[]
1717
successMessage?: string
1818
errorMessage?: string
1919
defaultUnselectedText?: string

src/components/DsfrTable/DsfrTable.stories.ts

Lines changed: 173 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ export default {
2424
control: 'boolean',
2525
description: 'Indique si la balise caption doit être visible (`false`, défaut) ou cachée (`true`)',
2626
},
27+
pagination: {
28+
control: 'boolean',
29+
description: 'Intègre une pagination au tableau',
30+
},
2731
headers: {
2832
control: 'object',
2933
description: 'Liste des en-têtes du tableau (tableau de string). Il existe un slot nommé `headers` pour gérer les en-têtes avec d’autres composants. C’est la même props attendue par <a href="/?path=/docs/composants-tableau-en-t%C3%AAtes-de-tableau-dsfrtableheaders--en-tetes-de-tableau">DsfrTableHeaders</a>',
@@ -40,6 +44,14 @@ export default {
4044
action: 'clicked on row',
4145
description: 'Fonction pour montrer le clic sur une ligne (Ici seulement la 2e ligne)',
4246
},
47+
defaultCurrentPage: {
48+
control: 'number',
49+
description: 'Le numéro de la page dans la pagination',
50+
},
51+
defaultOptionSelected: {
52+
control: 'number',
53+
description: 'La sélection du nombre d\'enregistrements par page',
54+
},
4355
},
4456
}
4557

@@ -49,9 +61,9 @@ const rows = [
4961
[
5062
'EGAUD',
5163
'Pierre-Louis',
52-
'pierre.egaud@ninja.com',
53-
'01 02 03 04 05',
54-
'06 01 02 03 04',
64+
'pierre.egaud@castor.fr',
65+
'02 04 06 08 10',
66+
'06 05 04 03 02',
5567
{
5668
component: 'DsfrTag',
5769
label: 'Erreur',
@@ -66,9 +78,9 @@ const rows = [
6678
rowData: [
6779
'DEBROIZE',
6880
'Clément',
69-
'clement.debroize@ninja.com',
70-
'01 02 03 04 05',
71-
'06 01 02 03 04',
81+
'clement.debroize@exile.com',
82+
'02 44 66 55 99',
83+
'07 88 77 22 33',
7284
{
7385
component: 'DsfrTag',
7486
label: 'Succès',
@@ -81,21 +93,168 @@ const rows = [
8193
'Stan',
8294
8395
{
84-
text: '01 02 03 04 05',
96+
text: '02 77 00 00 77',
8597
cellAttrs: {
8698
class: 'pointer',
8799
onClick: () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
88100
},
89101
},
90-
'06 01 02 03 04',
102+
'06 08 07 09 08',
103+
{
104+
component: 'DsfrTag',
105+
label: 'Info',
106+
class: 'info',
107+
},
108+
],
109+
[
110+
'MONTANA',
111+
'Tony',
112+
113+
'02 07 03 19 84',
114+
'06 07 03 19 84',
115+
{
116+
component: 'DsfrTag',
117+
label: 'Erreur',
118+
class: 'error',
119+
},
120+
],
121+
[
122+
'BOND',
123+
'James',
124+
125+
'02 00 07 19 62',
126+
'06 00 07 19 62',
127+
{
128+
component: 'DsfrTag',
129+
label: 'Succès',
130+
class: 'success',
131+
},
132+
],
133+
[
134+
'RAMBO',
135+
'John',
136+
137+
'02 00 00 19 82',
138+
'06 00 00 19 82',
139+
{
140+
component: 'DsfrTag',
141+
label: 'Info',
142+
class: 'info',
143+
},
144+
],
145+
[
146+
'CONNOR',
147+
'Sarah',
148+
149+
'02 00 00 19 84',
150+
'06 00 00 19 84',
151+
{
152+
component: 'DsfrTag',
153+
label: 'Erreur',
154+
class: 'error',
155+
},
156+
],
157+
[
158+
'KENOBI',
159+
'Obiwan',
160+
161+
'02 00 00 19 77',
162+
'06 00 00 19 77',
163+
{
164+
component: 'DsfrTag',
165+
label: 'Succès',
166+
class: 'success',
167+
},
168+
],
169+
[
170+
'KRUEGER',
171+
'Freddy',
172+
173+
'02 00 00 19 84',
174+
'06 00 00 19 84',
175+
{
176+
component: 'DsfrTag',
177+
label: 'Info',
178+
class: 'info',
179+
},
180+
],
181+
[
182+
'LEGRIS',
183+
'Gandalf',
184+
185+
'02 00 00 20 01',
186+
'06 00 00 20 01',
187+
{
188+
component: 'DsfrTag',
189+
label: 'Erreur',
190+
class: 'error',
191+
},
192+
],
193+
[
194+
'SÖZE',
195+
'Keyser',
196+
197+
'02 00 00 19 95',
198+
'06 00 00 19 95',
91199
{
92200
component: 'DsfrTag',
93201
label: 'Info',
94202
class: 'info',
95203
},
96204
],
205+
[
206+
'HUNT',
207+
'Ethan',
208+
209+
'02 00 00 19 96',
210+
'06 00 00 19 96',
211+
{
212+
component: 'DsfrTag',
213+
label: 'Erreur',
214+
class: 'error',
215+
},
216+
],
217+
[
218+
'HOLMES',
219+
'Sherlock',
220+
221+
'02 00 00 18 87',
222+
'06 00 00 18 87',
223+
{
224+
component: 'DsfrTag',
225+
label: 'Succès',
226+
class: 'success',
227+
},
228+
],
229+
[
230+
'JONES',
231+
'Indiana',
232+
233+
'02 00 00 19 81',
234+
'06 00 00 19 81',
235+
{
236+
component: 'DsfrTag',
237+
label: 'Info',
238+
class: 'info',
239+
},
240+
],
241+
[
242+
'WAYNE',
243+
'Bruce',
244+
245+
'02 00 00 19 89',
246+
'06 00 00 19 89',
247+
{
248+
component: 'DsfrTag',
249+
label: 'Erreur',
250+
class: 'error',
251+
},
252+
],
97253
]
98254
const noCaption = false
255+
const pagination = true
256+
const defaultCurrentPage = 2
257+
const defaultOptionSelected = 5
99258

100259
export const TableauEntier = (args) => ({
101260
components: {
@@ -120,6 +279,9 @@ export const TableauEntier = (args) => ({
120279
:headers="headers"
121280
:rows="rows"
122281
:no-caption="noCaption"
282+
:pagination="pagination"
283+
:defaultCurrentPage="defaultCurrentPage"
284+
:defaultOptionSelected="defaultOptionSelected"
123285
/>
124286
`,
125287

@@ -129,4 +291,7 @@ TableauEntier.args = {
129291
headers,
130292
rows,
131293
noCaption,
294+
pagination,
295+
defaultCurrentPage,
296+
defaultOptionSelected,
132297
}

src/components/DsfrTable/DsfrTable.vue

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,60 @@
11
<script lang="ts" setup>
2+
import { ref, watch } from 'vue'
23
import DsfrTableRow, { type DsfrTableRowProps } from './DsfrTableRow.vue'
34
import DsfrTableHeaders from './DsfrTableHeaders.vue'
45
import { type DsfrTableHeaderProps } from './DsfrTableHeader.vue'
56
6-
withDefaults(defineProps<{
7+
const props = withDefaults(defineProps<{
78
title?: string
89
headers?:(DsfrTableHeaderProps | string)[]
910
rows?: (DsfrTableRowProps | string)[]
1011
noCaption?: boolean
12+
pagination?: boolean
13+
defaultCurrentPage?: number
14+
defaultOptionSelected?: number
1115
}>(), {
1216
title: undefined,
1317
headers: () => [],
1418
rows: () => [],
19+
defaultCurrentPage: 1,
20+
defaultOptionSelected: 10,
1521
})
1622
1723
const getRowData = (row: (DsfrTableRowProps | string | ({component: string} & Record<string, any>))) => {
1824
// @ts-ignore TODO: find a way to improve types here
1925
return row.rowData || row
2026
}
27+
28+
const currentPage = ref(props.defaultCurrentPage)
29+
const optionSelected = ref(props.defaultOptionSelected)
30+
const pageCount = ref(props.rows.length > optionSelected.value ? Math.ceil(props.rows.length / optionSelected.value) : 1)
31+
const paginationOptions = [5, 10, 25, 50, 100]
32+
const returnLowestLimit = () => currentPage.value * optionSelected.value - optionSelected.value
33+
const returnHighestLimit = () => currentPage.value * optionSelected.value
34+
let truncatedResults = props.rows.slice(returnLowestLimit(), returnHighestLimit())
35+
36+
watch(() => optionSelected.value, (newVal, OldVal) => {
37+
props.rows.length > optionSelected.value ? pageCount.value = Math.ceil(props.rows.length / newVal) : pageCount.value = 1
38+
truncatedResults = props.rows.slice(returnLowestLimit(), returnHighestLimit())
39+
})
40+
41+
watch(() => currentPage.value, (newVal, OldVal) => {
42+
truncatedResults = props.rows.slice(returnLowestLimit(), returnHighestLimit())
43+
})
44+
45+
const goFirstPage = () => { currentPage.value = 1 }
46+
const goPreviousPage = () => {
47+
if (currentPage.value > 1) {
48+
currentPage.value -= 1
49+
}
50+
}
51+
const goNextPage = () => {
52+
if (currentPage.value < pageCount.value) {
53+
currentPage.value += 1
54+
}
55+
}
56+
const goLastPage = () => { currentPage.value = pageCount.value }
57+
2158
</script>
2259

2360
<template>
@@ -45,13 +82,72 @@ const getRowData = (row: (DsfrTableRowProps | string | ({component: string} & Re
4582
<slot />
4683
<template v-if="rows && rows.length">
4784
<DsfrTableRow
48-
v-for="(row, i) of rows"
85+
v-for="(row, i) of truncatedResults"
4986
:key="i"
5087
:row-data="getRowData(row)"
5188
:row-attrs="typeof row === 'string' ? {} : row.rowAttrs"
5289
/>
5390
</template>
91+
<tr v-if="pagination">
92+
<td :colspan="headers.length">
93+
<div class="flex justify-right">
94+
<div class="self-center">
95+
<span>Résultats par page : </span>
96+
<select
97+
v-model="optionSelected"
98+
>
99+
<option
100+
v-for="(option, idx) in paginationOptions"
101+
:key="idx"
102+
:value="option"
103+
>
104+
{{ option }}
105+
</option>
106+
</select>
107+
</div>
108+
<div class="flex ml-1">
109+
<span class="self-center">Page {{ currentPage }} sur {{ pageCount }}</span>
110+
</div>
111+
<div class="flex ml-1">
112+
<button
113+
class="fr-icon-arrow-left-s-first-line"
114+
@click="goFirstPage()"
115+
/>
116+
<button
117+
class="fr-icon-arrow-left-s-line-double"
118+
@click="goPreviousPage()"
119+
/>
120+
<button
121+
class="fr-icon-arrow-right-s-line-double"
122+
@click="goNextPage()"
123+
/>
124+
<button
125+
class="fr-icon-arrow-right-s-last-line"
126+
@click="goLastPage()"
127+
/>
128+
</div>
129+
</div>
130+
</td>
131+
</tr>
54132
</tbody>
55133
</table>
56134
</div>
57135
</template>
136+
137+
<style scoped>
138+
.flex {
139+
display: flex;
140+
}
141+
142+
.justify-right {
143+
justify-content: right;
144+
}
145+
146+
.ml-1 {
147+
margin-left: 1rem;
148+
}
149+
150+
.self-center {
151+
align-self: center;
152+
}
153+
</style>

0 commit comments

Comments
 (0)