Skip to content

Commit 3c2dab6

Browse files
authored
Merge pull request #42 from cloudblue/complex-table
Complex table
2 parents 24d0a91 + a8cc0f6 commit 3c2dab6

File tree

6 files changed

+294
-0
lines changed

6 files changed

+294
-0
lines changed

components/jest.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,12 @@ module.exports = {
4242
url: 'http://localhost/',
4343
customExportConditions: ["node", "node-addons"],
4444
},
45+
46+
globals: {
47+
'vue-jest': {
48+
compilerOptions: {
49+
isCustomElement: (tag) => tag.startsWith('ui-'),
50+
},
51+
},
52+
},
4553
};

components/src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import status from './widgets/status/widget.vue';
1212
import textfield from './widgets/textfield/widget.vue';
1313
import table from './widgets/table/widget.vue';
1414
import button from './widgets/button/widget.vue';
15+
import complexTable from './widgets/complexTable/widget.vue';
1516

1617
import _store from './core/store';
1718
import _bus from './core/eventBus';
@@ -30,6 +31,7 @@ export const Status = status;
3031
export const Textfield = textfield;
3132
export const Table = table;
3233
export const Button = button;
34+
export const ComplexTable = complexTable;
3335

3436
export const bus = _bus;
3537
export const store = _store;

components/src/widgets/button/widget.spec.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ describe('Button widget', () => {
1515
expect(result).toEqual(`
1616
background-color: #2C98F0;
1717
color: #FFF;
18+
height: auto;
19+
width: auto;
1820
`);
1921
});
2022
});

components/src/widgets/button/widget.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,21 @@ const emit = defineEmits(['clicked']);
3333
type: String,
3434
default: '#FFF',
3535
},
36+
height: {
37+
type: String,
38+
default: 'auto',
39+
},
40+
width: {
41+
type: String,
42+
default: 'auto',
43+
},
3644
});
3745
3846
const style = computed(() => `
3947
background-color: ${props.backgroundColor};
4048
color: ${props.color};
49+
height: ${props.height};
50+
width: ${props.width};
4151
`);
4252
4353
const onClick = () => {
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import { mount } from '@vue/test-utils'
2+
import ComplexTable from './widget';
3+
import { nextTick } from 'vue'
4+
5+
6+
describe('ComplexTable widget', () => {
7+
let result;
8+
9+
10+
describe('computed', () => {
11+
describe('#totalPages', () => {
12+
it('returns the total amount of pages', () => {
13+
const wrapper = mount(ComplexTable, {
14+
propsData: {
15+
totalItems: 35,
16+
items: ['hh'],
17+
headers: ['jj'],
18+
},
19+
})
20+
21+
result = wrapper.vm.totalPages;
22+
23+
expect(result).toEqual(4);
24+
});
25+
});
26+
27+
describe('#previousButtonDisabled', () => {
28+
it('returns true if the current page is 1', () => {
29+
const wrapper = mount(ComplexTable, {
30+
propsData: {
31+
totalItems: 35,
32+
items: ['hh'],
33+
headers: ['jj'],
34+
currentPage: 1,
35+
},
36+
})
37+
38+
result = wrapper.vm.previousButtonDisabled;
39+
40+
expect(result).toEqual(true);
41+
});
42+
43+
it('returns false if the current page is not 1', () => {
44+
const wrapper = mount(ComplexTable, {
45+
propsData: {
46+
totalItems: 35,
47+
items: ['hh'],
48+
headers: ['jj'],
49+
currentPage: 2,
50+
},
51+
})
52+
53+
result = wrapper.vm.previousButtonDisabled;
54+
55+
expect(result).toEqual(false);
56+
});
57+
});
58+
59+
describe('#nextButtonDisabled', () => {
60+
it('returns true if the current page is the last one', () => {
61+
const wrapper = mount(ComplexTable, {
62+
propsData: {
63+
totalItems: 25,
64+
items: ['hh'],
65+
headers: ['jj'],
66+
currentPage: 3,
67+
},
68+
})
69+
70+
result = wrapper.vm.nextButtonDisabled;
71+
72+
expect(result).toEqual(true);
73+
});
74+
75+
it('returns false if the current page is not the last one', () => {
76+
const wrapper = mount(ComplexTable, {
77+
propsData: {
78+
totalItems: 35,
79+
items: ['hh'],
80+
headers: ['jj'],
81+
currentPage: 2,
82+
},
83+
})
84+
85+
result = wrapper.vm.nextButtonDisabled;
86+
87+
expect(result).toEqual(false);
88+
});
89+
});
90+
});
91+
92+
describe('methods', () => {
93+
describe('#previousClicked', () => {
94+
it('emits previousClicked event', async () => {
95+
const wrapper = mount(ComplexTable, {
96+
propsData: {
97+
totalItems: 35,
98+
items: [],
99+
headers: ['jj'],
100+
currentPage: 2,
101+
},
102+
})
103+
104+
result = wrapper.vm.previousClicked();
105+
106+
expect(wrapper.emitted('previousClicked')).toBeTruthy()
107+
});
108+
});
109+
110+
describe('#nextClicked', () => {
111+
it('emits nextClicked event', async () => {
112+
const wrapper = mount(ComplexTable, {
113+
propsData: {
114+
totalItems: 35,
115+
items: [],
116+
headers: ['jj'],
117+
currentPage: 2,
118+
},
119+
})
120+
121+
result = wrapper.vm.nextClicked();
122+
123+
expect(wrapper.emitted('nextClicked')).toBeTruthy()
124+
});
125+
});
126+
127+
describe('#prepareItems', () => {
128+
it('returns the first 10 items', () => {
129+
const itemsList = ['1','2','3','4','5','6','7','8','9','10','11','12'];
130+
const wrapper = mount(ComplexTable, {
131+
propsData: {
132+
totalItems: 35,
133+
items: itemsList,
134+
headers: ['jj'],
135+
currentPage: 2,
136+
},
137+
})
138+
139+
result = wrapper.vm.prepareItems(itemsList);
140+
141+
expect(result.length).toEqual(10);
142+
});
143+
});
144+
});
145+
146+
describe('watch', () => {
147+
describe('props.items', () => {
148+
it('trigger the itemsLoaded event', async () => {
149+
const wrapper = mount(ComplexTable, {
150+
propsData: {
151+
totalItems: 35,
152+
items: [],
153+
headers: ['jj'],
154+
},
155+
})
156+
157+
wrapper.setProps({
158+
items: ['other']
159+
});
160+
161+
await nextTick()
162+
163+
expect(wrapper.emitted('itemsLoaded'))
164+
});
165+
});
166+
});
167+
});
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<template>
2+
<ui-table :headers="props.headers">
3+
<slot />
4+
</ui-table>
5+
<div class="buttons-container">
6+
<ui-button
7+
:disabled="previousButtonDisabled"
8+
class="previous-button"
9+
background-color="#fff"
10+
color="#161616"
11+
height="26px"
12+
width="80px"
13+
@clicked="previousClicked"
14+
>
15+
<div class="btn-text">
16+
Previous
17+
</div>
18+
</ui-button>
19+
<div>{{ currentPage }} / {{ totalPages }}</div>
20+
<ui-button
21+
:disabled="nextButtonDisabled"
22+
class="next-button"
23+
background-color="#fff"
24+
color="#161616"
25+
height="26px"
26+
width="56px"
27+
@clicked="nextClicked"
28+
>
29+
<div class="btn-text">
30+
Next
31+
</div>
32+
</ui-button>
33+
</div>
34+
</template>
35+
36+
<script setup>
37+
import { computed, watch } from 'vue';
38+
import table from '~widgets/table/widget.vue';
39+
import button from '~widgets/button/widget.vue';
40+
import registerWidget from '~core/registerWidget';
41+
42+
registerWidget('ui-table', table);
43+
registerWidget('ui-button', button);
44+
45+
const emit = defineEmits(['previousClicked', 'nextClicked', 'itemsLoaded']);
46+
const ITEMS_PER_PAGE = 10;
47+
const props = defineProps({
48+
headers: {
49+
type: Array,
50+
required: true,
51+
default: () => [],
52+
},
53+
items: {
54+
type: Array,
55+
required: true,
56+
default: () => [],
57+
},
58+
currentPage: {
59+
type: Number,
60+
default: 1,
61+
},
62+
totalItems: {
63+
type: Number,
64+
default: 1,
65+
}
66+
});
67+
68+
const totalPages = computed(() => Math.ceil(props.totalItems / ITEMS_PER_PAGE))
69+
const previousButtonDisabled = computed(() => props.currentPage === 1)
70+
const nextButtonDisabled = computed(() => props.currentPage === totalPages.value)
71+
72+
const previousClicked = () => emit('previousClicked');
73+
74+
const nextClicked = () => emit('nextClicked');
75+
76+
const prepareItems = (items) => {
77+
return items.slice(0, ITEMS_PER_PAGE)
78+
}
79+
80+
watch(() => props.items, function(newItems) {
81+
emit('itemsLoaded', prepareItems(newItems));
82+
}, { deep: true, immediate: true });
83+
</script>
84+
85+
<style lang="stylus" scoped>
86+
.buttons-container {
87+
display: flex;
88+
align-items: center;
89+
height: 48px;
90+
91+
.previous-button {
92+
margin-right: 16px;
93+
border: 1px solid #e0e0e0;
94+
}
95+
96+
.next-button {
97+
margin-left: 16px;
98+
border: 1px solid #e0e0e0;
99+
}
100+
101+
.btn-text {
102+
text-transform: capitalize;
103+
}
104+
}
105+
</style>

0 commit comments

Comments
 (0)