Skip to content

Commit 3348c89

Browse files
authored
[Remove Vuetify from Studio] Channel collection options
1 parent 70cb8da commit 3348c89

File tree

3 files changed

+135
-88
lines changed

3 files changed

+135
-88
lines changed

contentcuration/contentcuration/frontend/channelList/views/ChannelSet/ChannelSetItem.vue

Lines changed: 48 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -22,61 +22,31 @@
2222
{{ $formatNumber(channelCount) }}
2323
</td>
2424
<td class="text-xs-right">
25-
<BaseMenu>
26-
<template #activator="{ on }">
27-
<VBtn
28-
flat
29-
block
30-
v-on="on"
31-
>
32-
{{ $tr('options') }}
33-
<Icon icon="dropdown" />
34-
</VBtn>
35-
</template>
36-
<VList>
37-
<VListTile
38-
data-test="edit"
39-
:to="channelSetDetailsLink"
40-
>
41-
<VListTileAction>
42-
<Icon icon="edit" />
43-
</VListTileAction>
44-
<VListTileTitle>{{ $tr('edit') }}</VListTileTitle>
45-
</VListTile>
46-
<VListTile @click.prevent="deleteDialog = true">
47-
<VListTileAction>
48-
<Icon icon="trash" />
49-
</VListTileAction>
50-
<VListTileTitle>{{ $tr('delete') }}</VListTileTitle>
51-
</VListTile>
52-
</VList>
53-
</BaseMenu>
54-
<MessageDialog
55-
v-model="deleteDialog"
56-
:header="$tr('deleteChannelSetTitle')"
57-
:text="$tr('deleteChannelSetText')"
25+
<KButton
26+
:text="$tr('options')"
27+
appearance="flat-button"
28+
:hasDropdown="true"
5829
>
59-
<template #buttons="{ close }">
60-
<VSpacer />
61-
<VBtn
62-
flat
63-
color="primary"
64-
@click="close"
65-
>
66-
{{ $tr('cancel') }}
67-
</VBtn>
68-
<VBtn
69-
color="primary"
70-
data-test="delete"
71-
@click="
72-
deleteChannelSet(channelSet);
73-
close();
74-
"
75-
>
76-
{{ $tr('deleteChannelSetTitle') }}
77-
</VBtn>
30+
<template #menu>
31+
<KDropdownMenu
32+
:options="dropdownOptions"
33+
:hasIcons="true"
34+
:constrainToScrollParent="false"
35+
@select="handleOptionSelect"
36+
/>
7837
</template>
79-
</MessageDialog>
38+
</KButton>
39+
<KModal
40+
v-if="deleteDialog"
41+
:title="$tr('deleteChannelSetTitle')"
42+
:submitText="$tr('deleteChannelSetTitle')"
43+
:cancelText="$tr('cancel')"
44+
:appendToOverlay="true"
45+
@submit="handleDelete"
46+
@cancel="deleteDialog = false"
47+
>
48+
{{ $tr('deleteChannelSetText') }}
49+
</KModal>
8050
</td>
8151
</tr>
8252

@@ -87,13 +57,11 @@
8757
8858
import { mapActions, mapGetters } from 'vuex';
8959
import { RouteNames } from '../../constants';
90-
import MessageDialog from 'shared/views/MessageDialog';
9160
import CopyToken from 'shared/views/CopyToken';
9261
9362
export default {
9463
name: 'ChannelSetItem',
9564
components: {
96-
MessageDialog,
9765
CopyToken,
9866
},
9967
props: {
@@ -123,9 +91,34 @@
12391
? this.channelSet.channels.filter(c => c).length
12492
: 0;
12593
},
94+
dropdownOptions() {
95+
return [
96+
{
97+
label: this.$tr('edit'),
98+
value: 'edit',
99+
icon: 'edit',
100+
},
101+
{
102+
label: this.$tr('delete'),
103+
value: 'delete',
104+
icon: 'trash',
105+
},
106+
];
107+
},
126108
},
127109
methods: {
128110
...mapActions('channelSet', ['deleteChannelSet']),
111+
handleOptionSelect(option) {
112+
if (option.value === 'edit') {
113+
this.$router.push(this.channelSetDetailsLink);
114+
} else if (option.value === 'delete') {
115+
this.deleteDialog = true;
116+
}
117+
},
118+
handleDelete() {
119+
this.deleteChannelSet(this.channelSet);
120+
this.deleteDialog = false;
121+
},
129122
},
130123
$trs: {
131124
deleteChannelSetTitle: 'Delete collection',

contentcuration/contentcuration/frontend/channelList/views/ChannelSet/ChannelSetModal.vue

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,12 @@
9090
flat
9191
>
9292
<ChannelItem :channelId="channelId">
93-
<VBtn
94-
flat
95-
class="ma-0"
96-
color="primary"
93+
<KButton
94+
:text="$tr('removeText')"
95+
appearance="flat-button"
96+
:primary="true"
9797
@click="removeChannel(channelId)"
98-
>
99-
{{ $tr('removeText') }}
100-
</VBtn>
98+
/>
10199
</ChannelItem>
102100
</VCard>
103101
</div>
@@ -204,8 +202,8 @@
204202
import { generateFormMixin, constantsTranslationMixin, routerMixin } from 'shared/mixins';
205203
import CopyToken from 'shared/views/CopyToken';
206204
import FullscreenModal from 'shared/views/FullscreenModal';
207-
import Tabs from 'shared/views/Tabs';
208205
import StudioLargeLoader from 'shared/views/StudioLargeLoader';
206+
import Tabs from 'shared/views/Tabs';
209207
210208
const formMixin = generateFormMixin({
211209
name: {
Lines changed: 81 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,102 @@
1-
import { mount } from '@vue/test-utils';
2-
import { factory } from '../../../store';
3-
import router from '../../../router';
4-
import { RouteNames } from '../../../constants';
1+
import { render, screen } from '@testing-library/vue';
2+
import userEvent from '@testing-library/user-event';
3+
import { createLocalVue } from '@vue/test-utils';
4+
import Vuex, { Store } from 'vuex';
5+
import VueRouter from 'vue-router';
56
import ChannelSetItem from '../ChannelSetItem.vue';
7+
import { RouteNames } from '../../../constants';
68

7-
const store = factory();
9+
const localVue = createLocalVue();
10+
localVue.use(Vuex);
11+
localVue.use(VueRouter);
812

913
const channelSet = {
1014
id: 'testing',
15+
name: 'Test Collection',
1116
channels: [],
1217
secret_token: '1234567890',
1318
};
1419

15-
store.commit('channelSet/ADD_CHANNELSET', channelSet);
20+
const mockActions = {
21+
deleteChannelSet: jest.fn(() => Promise.resolve()),
22+
};
1623

17-
function makeWrapper() {
18-
const wrapper = mount(ChannelSetItem, {
19-
router,
24+
const createMockStore = () => {
25+
return new Store({
26+
modules: {
27+
channelSet: {
28+
namespaced: true,
29+
state: {
30+
channelSetsMap: {
31+
[channelSet.id]: channelSet,
32+
},
33+
},
34+
getters: {
35+
getChannelSet: state => id => state.channelSetsMap[id],
36+
},
37+
actions: mockActions,
38+
},
39+
},
40+
});
41+
};
42+
43+
const renderComponent = () => {
44+
const store = createMockStore();
45+
const router = new VueRouter({
46+
routes: [
47+
{
48+
name: RouteNames.CHANNEL_SET_DETAILS,
49+
path: '/channels/collections/:channelSetId',
50+
},
51+
],
52+
});
53+
54+
const result = render(ChannelSetItem, {
55+
localVue,
2056
store,
21-
sync: false,
22-
propsData: { channelSetId: channelSet.id },
57+
router,
58+
props: {
59+
channelSetId: channelSet.id,
60+
},
2361
});
24-
const deleteChannelSet = jest.spyOn(wrapper.vm, 'deleteChannelSet');
25-
deleteChannelSet.mockImplementation(() => Promise.resolve());
26-
return [wrapper, { deleteChannelSet }];
27-
}
2862

29-
describe('channelSetItem', () => {
30-
let wrapper, mocks;
63+
return { ...result, router };
64+
};
3165

66+
describe('channelSetItem', () => {
3267
beforeEach(() => {
33-
[wrapper, mocks] = makeWrapper();
68+
jest.clearAllMocks();
3469
});
3570

36-
it('clicking the edit option should open the channel set edit modal', () => {
37-
wrapper.find('[data-test="edit"]').trigger('click');
38-
expect(wrapper.vm.$route.name).toEqual(RouteNames.CHANNEL_SET_DETAILS);
71+
it('clicking the edit option should navigate to channel set details', async () => {
72+
const user = userEvent.setup();
73+
const { router } = renderComponent();
74+
75+
const optionsButton = screen.getByRole('button', { name: /options/i });
76+
await user.click(optionsButton);
77+
78+
const editOption = screen.getByText(/edit collection/i);
79+
await user.click(editOption);
80+
81+
expect(router.currentRoute.path).toBe(`/channels/collections/${channelSet.id}`);
3982
});
4083

41-
it('clicking delete button in dialog should delete the channel set', () => {
42-
wrapper.vm.deleteDialog = true;
43-
wrapper.find('[data-test="delete"]').trigger('click');
44-
expect(mocks.deleteChannelSet).toHaveBeenCalled();
84+
it('clicking delete button in dialog should delete the channel set', async () => {
85+
const user = userEvent.setup();
86+
renderComponent();
87+
88+
const optionsButton = screen.getByRole('button', { name: /options/i });
89+
await user.click(optionsButton);
90+
91+
const deleteOption = screen.getByText(/delete collection/i);
92+
await user.click(deleteOption);
93+
94+
const modalText = /are you sure you want to delete this collection/i;
95+
expect(screen.getByText(modalText)).toBeInTheDocument();
96+
97+
const confirmButton = screen.getByRole('button', { name: /delete collection/i });
98+
await user.click(confirmButton);
99+
100+
expect(mockActions.deleteChannelSet).toHaveBeenCalledWith(expect.any(Object), channelSet);
45101
});
46102
});

0 commit comments

Comments
 (0)