@ouestfrance/sipa-bms-ui 8.9.3 → 8.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sipa-bms-ui.css +39 -37
- package/dist/sipa-bms-ui.es.js +21 -17
- package/dist/sipa-bms-ui.es.js.map +1 -1
- package/dist/sipa-bms-ui.umd.js +21 -17
- package/dist/sipa-bms-ui.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/components/form/BmsTextArea.vue +1 -1
- package/src/components/form/UiBmsSwitch.vue +1 -0
- package/src/components/layout/BmsModal.stories.js +9 -0
- package/src/components/layout/BmsModal.vue +2 -0
- package/src/components/table/BmsPagination.spec.ts +114 -18
- package/src/components/table/BmsServerTable.vue +12 -9
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
:class="classes"
|
|
8
8
|
:required="required"
|
|
9
9
|
:placeholder="placeholder"
|
|
10
|
+
:disabled="disabled"
|
|
10
11
|
@input="onInput"
|
|
11
12
|
@keydown.enter.stop
|
|
12
13
|
cols="10"
|
|
@@ -93,7 +94,6 @@ defineExpose({
|
|
|
93
94
|
&.is-disabled {
|
|
94
95
|
--field-border-color: var(--bms-grey-25);
|
|
95
96
|
--textarea-background-color: var(--bms-grey-25);
|
|
96
|
-
pointer-events: none;
|
|
97
97
|
}
|
|
98
98
|
&.is-small {
|
|
99
99
|
min-height: 56px;
|
|
@@ -62,6 +62,7 @@ const Template = (args) => ({
|
|
|
62
62
|
</template>
|
|
63
63
|
<template #default>
|
|
64
64
|
<h3>This is content</h3>
|
|
65
|
+
<p v-html="args.content"/>
|
|
65
66
|
<BmsProblem
|
|
66
67
|
v-if="args.openNotification"
|
|
67
68
|
:problem="args.openNotification"
|
|
@@ -80,6 +81,14 @@ Default.args = {
|
|
|
80
81
|
title: 'Titre',
|
|
81
82
|
};
|
|
82
83
|
|
|
84
|
+
export const WithScroll = Template.bind({});
|
|
85
|
+
WithScroll.args = {
|
|
86
|
+
modelValue: true,
|
|
87
|
+
title: 'Titre',
|
|
88
|
+
content:
|
|
89
|
+
'This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>This is a big content for scrolling<br/>',
|
|
90
|
+
};
|
|
91
|
+
|
|
83
92
|
export const Success = Template.bind({});
|
|
84
93
|
Success.args = {
|
|
85
94
|
modelValue: true,
|
|
@@ -267,6 +267,7 @@ onUnmounted(() => {
|
|
|
267
267
|
align-items: center;
|
|
268
268
|
justify-content: center;
|
|
269
269
|
background: var(--bms-white);
|
|
270
|
+
z-index: calc(var(--bms-z-index-fixed) + 5);
|
|
270
271
|
|
|
271
272
|
p {
|
|
272
273
|
margin: 0;
|
|
@@ -308,6 +309,7 @@ onUnmounted(() => {
|
|
|
308
309
|
margin: -1em;
|
|
309
310
|
position: sticky;
|
|
310
311
|
background: var(--bms-white);
|
|
312
|
+
z-index: var(--bms-z-index-fixed);
|
|
311
313
|
}
|
|
312
314
|
|
|
313
315
|
&__header {
|
|
@@ -1,26 +1,74 @@
|
|
|
1
|
-
import BmsPagination from '@/components/table/BmsPagination.vue';
|
|
2
|
-
import { field } from '@/plugins/field';
|
|
3
1
|
import { mount, shallowMount } from '@vue/test-utils';
|
|
2
|
+
import { describe, test, expect, vi, beforeEach } from 'vitest';
|
|
3
|
+
import BmsPagination from './BmsPagination.vue';
|
|
4
4
|
|
|
5
|
+
// Mock field plugin
|
|
6
|
+
const mockField = {
|
|
7
|
+
install: vi.fn(),
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// Mock IntersectionObserver
|
|
5
11
|
const intersectionObserverMock = () => ({
|
|
6
12
|
observe: () => null,
|
|
7
13
|
});
|
|
8
14
|
|
|
15
|
+
// Mock child components
|
|
16
|
+
vi.mock('@/components/button/BmsIconButton.vue', () => ({
|
|
17
|
+
default: {
|
|
18
|
+
name: 'BmsIconButton',
|
|
19
|
+
template: '<button><slot /></button>',
|
|
20
|
+
props: ['color', 'disabled'],
|
|
21
|
+
},
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
vi.mock('@/index', () => ({
|
|
25
|
+
BmsSelect: {
|
|
26
|
+
name: 'BmsSelect',
|
|
27
|
+
template:
|
|
28
|
+
'<select><option v-for="option in options" :key="option.value" :value="option.value">{{ option.label }}</option></select>',
|
|
29
|
+
props: ['modelValue', 'options'],
|
|
30
|
+
emits: ['update:modelValue'],
|
|
31
|
+
},
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
vi.mock('lucide-vue-next', () => ({
|
|
35
|
+
ChevronFirst: { name: 'ChevronFirst', template: '<span>First</span>' },
|
|
36
|
+
ChevronLast: { name: 'ChevronLast', template: '<span>Last</span>' },
|
|
37
|
+
ChevronLeft: { name: 'ChevronLeft', template: '<span>Left</span>' },
|
|
38
|
+
ChevronRight: { name: 'ChevronRight', template: '<span>Right</span>' },
|
|
39
|
+
}));
|
|
40
|
+
|
|
9
41
|
const shallowFactory = (props: any) => {
|
|
10
42
|
return shallowMount(BmsPagination, {
|
|
11
43
|
global: {
|
|
12
|
-
plugins: [
|
|
44
|
+
plugins: [mockField],
|
|
13
45
|
},
|
|
14
|
-
|
|
46
|
+
props: { ...props },
|
|
15
47
|
});
|
|
16
48
|
};
|
|
17
49
|
|
|
18
50
|
const factory = (props: any) => {
|
|
19
51
|
return mount(BmsPagination, {
|
|
20
52
|
global: {
|
|
21
|
-
plugins: [
|
|
53
|
+
plugins: [mockField],
|
|
54
|
+
stubs: {
|
|
55
|
+
BmsSelect: {
|
|
56
|
+
name: 'BmsSelect',
|
|
57
|
+
template:
|
|
58
|
+
'<select v-model="modelValue"><option v-for="option in options" :key="option.value" :value="option.value">{{ option.label }}</option></select>',
|
|
59
|
+
props: ['modelValue', 'options'],
|
|
60
|
+
emits: ['update:modelValue'],
|
|
61
|
+
},
|
|
62
|
+
BmsIconButton: {
|
|
63
|
+
name: 'BmsIconButton',
|
|
64
|
+
template:
|
|
65
|
+
'<button @click="$emit(\'click\')" :disabled="disabled"><slot /></button>',
|
|
66
|
+
props: ['color', 'disabled'],
|
|
67
|
+
emits: ['click'],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
22
70
|
},
|
|
23
|
-
|
|
71
|
+
props: { ...props },
|
|
24
72
|
});
|
|
25
73
|
};
|
|
26
74
|
|
|
@@ -31,7 +79,8 @@ describe('BmsPagination', () => {
|
|
|
31
79
|
.fn()
|
|
32
80
|
.mockImplementation(intersectionObserverMock);
|
|
33
81
|
});
|
|
34
|
-
|
|
82
|
+
|
|
83
|
+
test('should display correctly', () => {
|
|
35
84
|
const wrapper = shallowFactory({
|
|
36
85
|
sizes: [25, 50],
|
|
37
86
|
total: 120,
|
|
@@ -40,10 +89,10 @@ describe('BmsPagination', () => {
|
|
|
40
89
|
pages: Math.ceil(120 / 25),
|
|
41
90
|
});
|
|
42
91
|
|
|
43
|
-
expect(wrapper.text()).toContain('
|
|
92
|
+
expect(wrapper.text()).toContain('1 à 25');
|
|
44
93
|
});
|
|
45
94
|
|
|
46
|
-
|
|
95
|
+
test('should emit correct navigation events', async () => {
|
|
47
96
|
const wrapper = factory({
|
|
48
97
|
sizes: [25, 50],
|
|
49
98
|
total: 120,
|
|
@@ -52,22 +101,69 @@ describe('BmsPagination', () => {
|
|
|
52
101
|
pages: Math.ceil(120 / 25),
|
|
53
102
|
});
|
|
54
103
|
|
|
55
|
-
const
|
|
56
|
-
const goToBeginning =
|
|
57
|
-
const goBack =
|
|
58
|
-
const goForward =
|
|
59
|
-
const goToEnding =
|
|
104
|
+
const buttons = wrapper.findAllComponents({ name: 'BmsIconButton' });
|
|
105
|
+
const goToBeginning = buttons[0];
|
|
106
|
+
const goBack = buttons[1];
|
|
107
|
+
const goForward = buttons[2];
|
|
108
|
+
const goToEnding = buttons[3];
|
|
60
109
|
|
|
61
110
|
await goToBeginning.trigger('click');
|
|
62
|
-
expect(wrapper.emitted()
|
|
111
|
+
expect(wrapper.emitted('go')?.[0]).toEqual([0]);
|
|
63
112
|
|
|
64
113
|
await goBack.trigger('click');
|
|
65
|
-
expect(wrapper.emitted()
|
|
114
|
+
expect(wrapper.emitted('prev')?.[0]).toEqual([]);
|
|
66
115
|
|
|
67
116
|
await goForward.trigger('click');
|
|
68
|
-
expect(wrapper.emitted()
|
|
117
|
+
expect(wrapper.emitted('next')?.[0]).toEqual([]);
|
|
69
118
|
|
|
70
119
|
await goToEnding.trigger('click');
|
|
71
|
-
expect(wrapper.emitted()
|
|
120
|
+
expect(wrapper.emitted('go')?.[1]).toEqual([4]);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('should handle size change', async () => {
|
|
124
|
+
const wrapper = factory({
|
|
125
|
+
sizes: [25, 50],
|
|
126
|
+
total: 120,
|
|
127
|
+
currentPage: 0,
|
|
128
|
+
currentSize: 25,
|
|
129
|
+
pages: Math.ceil(120 / 25),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const select = wrapper.findComponent({ name: 'BmsSelect' });
|
|
133
|
+
await select.vm.$emit('update:modelValue', 50);
|
|
134
|
+
|
|
135
|
+
expect(wrapper.emitted('update:currentSize')?.[0]).toEqual([50]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('should disable navigation buttons correctly', () => {
|
|
139
|
+
const wrapper = factory({
|
|
140
|
+
sizes: [25, 50],
|
|
141
|
+
total: 120,
|
|
142
|
+
currentPage: 0,
|
|
143
|
+
currentSize: 25,
|
|
144
|
+
pages: Math.ceil(120 / 25),
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const buttons = wrapper.findAllComponents({ name: 'BmsIconButton' });
|
|
148
|
+
|
|
149
|
+
// First and previous buttons should be disabled on first page
|
|
150
|
+
expect(buttons[0].props('disabled')).toBe(true);
|
|
151
|
+
expect(buttons[1].props('disabled')).toBe(true);
|
|
152
|
+
|
|
153
|
+
// Next and last buttons should be enabled
|
|
154
|
+
expect(buttons[2].props('disabled')).toBe(false);
|
|
155
|
+
expect(buttons[3].props('disabled')).toBe(false);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('should calculate last item number correctly', () => {
|
|
159
|
+
const wrapper = shallowFactory({
|
|
160
|
+
sizes: [25, 50],
|
|
161
|
+
total: 120,
|
|
162
|
+
currentPage: 1,
|
|
163
|
+
currentSize: 25,
|
|
164
|
+
pages: Math.ceil(120 / 25),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
expect(wrapper.text()).toContain('26 à 50');
|
|
72
168
|
});
|
|
73
169
|
});
|
|
@@ -112,7 +112,6 @@ const props = withDefaults(defineProps<UiTableProps>(), {
|
|
|
112
112
|
signal: controller.signal,
|
|
113
113
|
},
|
|
114
114
|
);
|
|
115
|
-
|
|
116
115
|
const totalItems = response.headers.get('X-Total');
|
|
117
116
|
const data = await response.json();
|
|
118
117
|
return { data, total: totalItems ? parseInt(totalItems) : Infinity };
|
|
@@ -211,13 +210,21 @@ watch(
|
|
|
211
210
|
{ deep: true },
|
|
212
211
|
);
|
|
213
212
|
|
|
213
|
+
// Watch vuejs cannot call directly the debounce function
|
|
214
|
+
const debouncedHandler = _debounce((callBack) => {
|
|
215
|
+
callBack();
|
|
216
|
+
}, props.debounceTime);
|
|
217
|
+
|
|
214
218
|
watch(
|
|
215
219
|
[() => filters.value, () => sort.value, size, search],
|
|
216
220
|
() => {
|
|
217
221
|
if (!isMounting.value) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
222
|
+
const callBack = () => {
|
|
223
|
+
currentPage.value = props.initialPage;
|
|
224
|
+
emits('update:selectMode', SelectMode.DEFAULT);
|
|
225
|
+
fetchData();
|
|
226
|
+
};
|
|
227
|
+
debouncedHandler(callBack);
|
|
221
228
|
}
|
|
222
229
|
},
|
|
223
230
|
{ deep: true },
|
|
@@ -268,10 +275,6 @@ async function fetchData() {
|
|
|
268
275
|
}
|
|
269
276
|
}
|
|
270
277
|
|
|
271
|
-
const debouncedSearch = _debounce((value: string) => {
|
|
272
|
-
search.value = value;
|
|
273
|
-
}, props.debounceTime);
|
|
274
|
-
|
|
275
278
|
const onPrevClick = () => {
|
|
276
279
|
goToPage(currentPage.value - 1, total.value);
|
|
277
280
|
};
|
|
@@ -375,7 +378,7 @@ const onSelectAll = () => emits('update:selectMode', SelectMode.ALL);
|
|
|
375
378
|
<BmsSearch
|
|
376
379
|
:modelValue="search"
|
|
377
380
|
class="table-search"
|
|
378
|
-
@update:modelValue="
|
|
381
|
+
@update:modelValue="search = $event"
|
|
379
382
|
/>
|
|
380
383
|
</slot>
|
|
381
384
|
</template>
|