@eturnity/eturnity_reusable_components 7.39.1 → 7.39.3

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_reusable_components",
3
- "version": "7.39.1",
3
+ "version": "7.39.3",
4
4
  "files": [
5
5
  "dist",
6
6
  "src"
@@ -0,0 +1,45 @@
1
+ import ActionBanner from './index.vue'
2
+ import theme from '@/assets/theme'
3
+ export default {
4
+ title: 'ActionBanner',
5
+ component: ActionBanner,
6
+ tags: ['autodocs'],
7
+ }
8
+
9
+ // <RCActionBanner
10
+ // :isOpen="true"
11
+ // @on-close="handleClose"
12
+ // >
13
+ // <template #title>Sample title</template>
14
+ // <template #body>Sample body</template>
15
+ // <template #buttons>
16
+ // <button>Sample button </button>
17
+ // </template>
18
+ // </RCActionBanner>
19
+
20
+ export const Default = {
21
+ args: {
22
+ isOpen: false,
23
+ },
24
+ }
25
+
26
+ export const OpenedActionBanner = {
27
+ args: {
28
+ isOpen: true,
29
+ },
30
+ render: (args) => ({
31
+ components: { ActionBanner },
32
+ setup() {
33
+ return { args }
34
+ },
35
+ template: `
36
+ <ActionBanner v-bind="args">
37
+ <template #title>Sample title</template>
38
+ <template #body>Sample body</template>
39
+ <template #buttons>
40
+ <button>Sample button </button>
41
+ </template>
42
+ </ActionBanner>
43
+ `,
44
+ }),
45
+ }
@@ -0,0 +1,76 @@
1
+ /* eslint-disable */
2
+ import { h } from 'vue'
3
+ import { mount } from '@vue/test-utils'
4
+ import ActionBanner from '@/components/banner/actionBanner'
5
+ import theme from '@/assets/theme'
6
+
7
+ describe('Action Banner Component', () => {
8
+ it('action banner is shown when isOpen props is true', async () => {
9
+ const wrapper = mount(ActionBanner, {
10
+ props: {
11
+ isOpen: false,
12
+ },
13
+ global: {
14
+ provide: {
15
+ theme,
16
+ },
17
+ },
18
+ })
19
+
20
+ const bannerWrapper = wrapper.find('[data-test-id="action_banner_wrapper"]')
21
+ expect(bannerWrapper.exists()).toBe(true)
22
+ expect(bannerWrapper.classes()).not.toContain('visible')
23
+ expect(bannerWrapper.classes()).toContain('hidden')
24
+ await wrapper.setProps({ isOpen: true })
25
+ expect(bannerWrapper.classes()).toContain('visible')
26
+ expect(bannerWrapper.classes()).not.toContain('hidden')
27
+ })
28
+
29
+ it('action banner slots is display when user passed slots content', async () => {
30
+ const titleText = 'Sample title'
31
+ const bodyText = 'Sample body text'
32
+ const buttonText = 'Sample button'
33
+
34
+ const wrapper = mount(ActionBanner, {
35
+ props: {
36
+ isOpen: false,
37
+ },
38
+ slots: {
39
+ title: titleText,
40
+ body: bodyText,
41
+ buttons: h('button', {}, buttonText),
42
+ },
43
+ global: {
44
+ provide: {
45
+ theme,
46
+ },
47
+ },
48
+ })
49
+
50
+ const modalTitleEl = wrapper.find('[data-test-id="modal_title"]')
51
+ expect(modalTitleEl.text()).toBe(titleText)
52
+ const modalBodyEl = wrapper.find('[data-test-id="modal_body"]')
53
+ expect(modalBodyEl.text()).toBe(bodyText)
54
+ const modalButtonsEl = wrapper.find('[data-test-id="modal_buttons"]')
55
+ expect(modalButtonsEl.text()).toBe(buttonText)
56
+ })
57
+
58
+ it('action banner on-close event is emitted when modal close button is clicked', async () => {
59
+ const wrapper = mount(ActionBanner, {
60
+ props: {
61
+ isOpen: true,
62
+ },
63
+ global: {
64
+ provide: {
65
+ theme,
66
+ },
67
+ },
68
+ })
69
+
70
+ const modalCloseButton = wrapper.find('.close')
71
+ await modalCloseButton.trigger('click')
72
+ expect(wrapper.emitted('on-close')).toBeTruthy()
73
+ const emittedEvent = wrapper.emitted('on-close')
74
+ expect(emittedEvent).toHaveLength(1)
75
+ })
76
+ })
@@ -1,21 +1,37 @@
1
1
  <template>
2
- <Modal :is-open="isOpen" @on-close="closeModal">
2
+ <Modal
3
+ :is-open="isOpen"
4
+ data-test-id="action_banner_wrapper"
5
+ @on-close="closeModal"
6
+ >
3
7
  <ModalContainer>
4
- <ModalTitle v-if="$slots.title">
8
+ <ModalTitle v-if="$slots.title" data-test-id="modal_title">
5
9
  <slot name="title"></slot>
6
10
  </ModalTitle>
7
- <TextContainer v-if="$slots.body">
11
+ <TextContainer v-if="$slots.body" data-test-id="modal_body">
8
12
  <slot name="body"></slot>
9
13
  </TextContainer>
10
- <ButtonContainer v-if="$slots.buttons">
14
+ <ButtonContainer v-if="$slots.buttons" data-test-id="modal_buttons">
11
15
  <slot name="buttons"></slot>
12
16
  </ButtonContainer>
13
17
  </ModalContainer>
14
18
  </Modal>
15
19
  </template>
16
20
  <script>
21
+ // import RCBanner from "@eturnity/eturnity_reusable_components/src/components/banner/actionBanner"
22
+ // <RCActionBanner
23
+ // :isOpen="true"
24
+ // @on-close="handleClose"
25
+ // >
26
+ // <template #title>Sample title</template>
27
+ // <template #body>Sample body</template>
28
+ // <template #buttons>
29
+ // <button>Sample button </button>
30
+ // </template>
31
+ // </RCActionBanner>
32
+
17
33
  import styled from 'vue3-styled-components'
18
- import Modal from '../modal'
34
+ import Modal from '@/components/modals/modal'
19
35
  const ModalContainer = styled.div`
20
36
  width: 450px;
21
37
  min-height: 205px;
@@ -23,7 +39,7 @@
23
39
  `
24
40
  const ModalTitle = styled.div`
25
41
  color: ${(props) => props.theme.colors.black};
26
- font-family: ${(props) => props.theme.fonts.mainFont};
42
+ font-family: inherit;
27
43
  font-size: 18px;
28
44
  font-style: normal;
29
45
  font-weight: 700;
@@ -37,7 +53,7 @@
37
53
  `
38
54
  const TextContainer = styled.div`
39
55
  color: ${(props) => props.theme.colors.black};
40
- font-family: ${(props) => props.theme.fonts.mainFont};
56
+ font-family: inherit;
41
57
  font-size: 13px;
42
58
  font-style: normal;
43
59
  font-weight: 400;
@@ -45,6 +61,7 @@
45
61
  padding: 30px 0px;
46
62
  white-space: pre-wrap;
47
63
  `
64
+
48
65
  export default {
49
66
  name: 'ActionModal',
50
67
  components: {
@@ -54,7 +71,12 @@
54
71
  ButtonContainer,
55
72
  TextContainer,
56
73
  },
57
- props: ['isOpen'],
74
+ props: {
75
+ isOpen: {
76
+ type: Boolean,
77
+ default: false,
78
+ },
79
+ },
58
80
  methods: {
59
81
  closeModal() {
60
82
  this.$emit('on-close')
@@ -0,0 +1,64 @@
1
+ import Banner from './index.vue'
2
+ import theme from '@/assets/theme'
3
+
4
+ export default {
5
+ title: 'Banner',
6
+ component: Banner,
7
+ tags: ['autodocs'],
8
+ }
9
+
10
+ // To use:
11
+ // <RCBanner
12
+ // backdrop="white" // white, dark
13
+ // :hideClose="true"
14
+ // :isLoading="true"
15
+ // :isOpen="true"
16
+ // position="fixed"
17
+ // stopPropagation="false"
18
+ // @on-close="handleClose"
19
+ // />
20
+
21
+ export const Default = {
22
+ args: {
23
+ isOpen: false,
24
+ isLoading: false,
25
+ hideClose: false,
26
+ backdrop: 'white',
27
+ position: 'fixed',
28
+ stopPropagation: true,
29
+ },
30
+ }
31
+
32
+ export const OpenedBanner = {
33
+ args: {
34
+ isOpen: true,
35
+ },
36
+ }
37
+
38
+ export const LoadingBanner = {
39
+ args: {
40
+ isOpen: true,
41
+ isLoading: true,
42
+ },
43
+ }
44
+
45
+ export const HiddenCloseButton = {
46
+ args: {
47
+ isOpen: true,
48
+ hideClose: true,
49
+ },
50
+ }
51
+
52
+ export const DarkBackdrop = {
53
+ args: {
54
+ isOpen: true,
55
+ backdrop: 'dark',
56
+ },
57
+ }
58
+
59
+ export const AbsolutePositionBanner = {
60
+ args: {
61
+ isOpen: true,
62
+ position: 'absolute',
63
+ },
64
+ }
@@ -0,0 +1,149 @@
1
+ /* eslint-disable */
2
+ import { mount } from '@vue/test-utils'
3
+ import Banner from '@/components/banner/banner'
4
+ import theme from '@/assets/theme'
5
+
6
+ describe('Banner Component', () => {
7
+ it('banner is shown when isOpen props is true', async () => {
8
+ // Start with isOpen as false
9
+ const wrapper = mount(Banner, {
10
+ props: {
11
+ isOpen: false,
12
+ isLoading: false,
13
+ },
14
+ global: {
15
+ provide: {
16
+ theme,
17
+ },
18
+ },
19
+ })
20
+
21
+ const bannerWrapper = wrapper.find('[data-test-id="banner_wrapper"]')
22
+ // check that the element exists with correct props
23
+ expect(bannerWrapper.exists()).toBe(true)
24
+ // Check if wrapper doesnt have the 'visible' class, and have 'hidden' class
25
+ expect(bannerWrapper.classes()).not.toContain('visible')
26
+ expect(bannerWrapper.classes()).toContain('hidden')
27
+ // Now, set isOpen to true
28
+ await wrapper.setProps({ isOpen: true })
29
+ // Check if the 'visible' class is applied and 'hidden' class is not applied
30
+ expect(bannerWrapper.classes()).toContain('visible')
31
+ expect(bannerWrapper.classes()).not.toContain('hidden')
32
+ })
33
+
34
+ it('banner spinner is shown when user set isLoading props is true', async () => {
35
+ // Start with isLoading is false
36
+ const wrapper = mount(Banner, {
37
+ props: {
38
+ isOpen: true,
39
+ isLoading: false,
40
+ },
41
+ global: {
42
+ provide: {
43
+ theme,
44
+ },
45
+ },
46
+ })
47
+
48
+ const bannerWrapper = wrapper.find('[data-test-id="banner_wrapper"]')
49
+ // Initial check, spinner should not exist
50
+ let spinnerElement = bannerWrapper.find('[data-test-id="banner_spinner"]')
51
+ expect(spinnerElement.exists()).toBe(false)
52
+ // Set isLoading to true
53
+ await wrapper.setProps({ isLoading: true })
54
+ await wrapper.vm.$nextTick()
55
+ // Find the spinner element again after updating the prop and check if it exsit
56
+ spinnerElement = bannerWrapper.find('[data-test-id="banner_spinner"]')
57
+ expect(spinnerElement.exists()).toBe(true)
58
+ })
59
+
60
+ it('banner close button is not shown when hideClose props is true', async () => {
61
+ // Set hideClose to false
62
+ const wrapper = mount(Banner, {
63
+ props: {
64
+ isOpen: true,
65
+ hideClose: false,
66
+ },
67
+ global: {
68
+ provide: {
69
+ theme,
70
+ },
71
+ },
72
+ })
73
+
74
+ const bannerWrapper = wrapper.find('[data-test-id="banner_wrapper"]')
75
+
76
+ // Initial check, closeButton should exist
77
+ let closeButton = bannerWrapper.find('[data-test-id="banner_close_button"]')
78
+ expect(closeButton.exists()).toBe(true)
79
+ // Set isLoading to true
80
+ await wrapper.setProps({ hideClose: true })
81
+ await wrapper.vm.$nextTick()
82
+ // Find the closeButton element again after updating the prop
83
+ closeButton = bannerWrapper.find('[data-test-id="banner_close_button"]')
84
+ // Check if closeButton does not exist now
85
+ expect(closeButton.exists()).toBe(false)
86
+ })
87
+
88
+ it('banner on-close event is emitted when close button is clicked', async () => {
89
+ const wrapper = mount(Banner, {
90
+ props: {
91
+ isOpen: true,
92
+ },
93
+ global: {
94
+ provide: {
95
+ theme,
96
+ },
97
+ },
98
+ })
99
+
100
+ const bannerWrapper = wrapper.find('[data-test-id="banner_wrapper"]')
101
+ // Find the close button element
102
+ const closeButton = bannerWrapper.find(
103
+ '[data-test-id="banner_close_button"]'
104
+ )
105
+ // Simulate a click and check if the component emmitted a on-close event
106
+ await closeButton.trigger('click')
107
+ expect(wrapper.emitted('on-close')).toBeTruthy()
108
+ const emittedEvent = wrapper.emitted('on-close')
109
+ expect(emittedEvent).toHaveLength(1)
110
+ })
111
+
112
+ it('event.stopPropagation is called when stopPropagation prop is true and banner wrapper is clicked', async () => {
113
+ const wrapper = mount(Banner, {
114
+ props: {
115
+ isOpen: true,
116
+ stopPropagation: true,
117
+ },
118
+ global: {
119
+ provide: {
120
+ theme,
121
+ },
122
+ },
123
+ })
124
+
125
+ const bannerWrapper = wrapper.find('[data-test-id="banner_wrapper"]')
126
+ let modalWrapper = bannerWrapper.find('[data-test-id="modal-container"]')
127
+ // Mock for event.stopPropagation
128
+ const stopPropagationMock = jest.fn()
129
+ // Simulate a click event with the mocked stopPropagation function
130
+ await modalWrapper.trigger('click', {
131
+ stopPropagation: stopPropagationMock,
132
+ })
133
+ // Check if stopPropagation was called
134
+ expect(stopPropagationMock).toHaveBeenCalled()
135
+
136
+ // Set stopPropagation props to false and wait for the DOM to update
137
+ await wrapper.setProps({ stopPropagation: false })
138
+ await wrapper.vm.$nextTick()
139
+
140
+ // Create new mock for event.stopPropagation that should not be called
141
+ const stopPropagationNotCalledMock = jest.fn()
142
+ // Simulate againma click event
143
+ await modalWrapper.trigger('click', {
144
+ stopPropagation: stopPropagationNotCalledMock,
145
+ })
146
+ // Check if stopPropagation was NOT called
147
+ expect(stopPropagationNotCalledMock).not.toHaveBeenCalled()
148
+ })
149
+ })
@@ -2,29 +2,45 @@
2
2
  <PageWrapper
3
3
  :backdrop="backdrop"
4
4
  :class="{ visible: isOpen, hidden: !isOpen }"
5
+ data-test-id="banner_wrapper"
5
6
  :is-open="isOpen"
6
7
  :position="position"
7
8
  >
8
- <ModalContainer @click="onClickModalContainer">
9
- <Spinner v-if="isLoading" :limited-to-modal="true" size="50px" />
9
+ <ModalContainer
10
+ data-test-id="modal-container"
11
+ @click="onClickModalContainer"
12
+ >
13
+ <Spinner
14
+ v-if="isLoading"
15
+ data-test-id="banner_spinner"
16
+ :limited-to-modal="true"
17
+ size="50px"
18
+ />
10
19
  <ContentContainer :visible="!isLoading">
11
20
  <slot></slot>
12
21
  </ContentContainer>
13
- <CloseButton v-if="!hideClose" class="close" @click="onCloseModal()" />
22
+ <CloseButton
23
+ v-if="!hideClose"
24
+ class="close"
25
+ data-test-id="banner_close_button"
26
+ @click="onCloseModal()"
27
+ />
14
28
  </ModalContainer>
15
29
  </PageWrapper>
16
30
  </template>
17
31
 
18
32
  <script>
19
- // Rules: (as defined in https://e-turnity.atlassian.net/browse/EPDM-9694)
20
- // 1. On clicking the “escape” key, close the modal onCloseModal()
21
- // 2. Always prevent outside close
22
- // import Modal from "@eturnity/eturnity_reusable_components/src/components/modals/modal"
23
- // This is a more flexible modal box, where the parent can decide how the body of the modal looks
24
33
  // To use:
25
- // <modal :isOpen="isOpen" @on-close="$emit('on-close-summary')" :isLoading="true" :hideClose="true" :stopPropagation="false">
26
- // <div>Data....</div>
27
- // </modal>
34
+ // import RCBanner from "@eturnity/eturnity_reusable_components/src/components/banner/banner"
35
+ // <RCBanner
36
+ // backdrop="white" // white, dark
37
+ // :hideClose="true"
38
+ // :isLoading="true"
39
+ // :isOpen="true"
40
+ // position="fixed"
41
+ // stopPropagation="false"
42
+ // @on-close="handleClose"
43
+ // />
28
44
 
29
45
  import styled from 'vue3-styled-components'
30
46
  import CloseButton from '../../buttons/closeButton'
@@ -33,6 +49,7 @@
33
49
  const contentAttrs = { visible: Boolean }
34
50
  const ContentContainer = styled('div', contentAttrs)`
35
51
  visibility: ${(props) => (props.visible ? 'inherit' : 'hidden')};
52
+ color: red;
36
53
  `
37
54
 
38
55
  const pageAttrs = { isOpen: Boolean, backdrop: String, position: String }
@@ -129,23 +146,23 @@
129
146
  },
130
147
  props: {
131
148
  isOpen: {
132
- required: true,
149
+ type: Boolean,
133
150
  default: false,
134
151
  },
135
152
  isLoading: {
136
- required: false,
153
+ type: Boolean,
137
154
  default: false,
138
155
  },
139
156
  hideClose: {
140
- required: false,
157
+ type: Boolean,
141
158
  default: false,
142
159
  },
143
160
  backdrop: {
144
- required: false,
161
+ type: String,
145
162
  default: 'white',
146
163
  },
147
164
  position: {
148
- required: false,
165
+ type: String,
149
166
  default: 'fixed',
150
167
  },
151
168
  stopPropagation: {
@@ -1,50 +1,9 @@
1
1
  <template>
2
2
  <PageWrapper>
3
- <PageContainer v-if="!expanded">
4
- <BoxContainer>
5
- <SelectedContainer>
6
- {{ numberSelected }} {{ $gettext('selected') }}
7
- </SelectedContainer>
8
- <ListContainer v-if="optionsList.length">
9
- <ListItem
10
- v-for="item in limitedOptions"
11
- :key="item.type"
12
- :disabled="item.disabled || false"
13
- :hover-color="item.hoverColor"
14
- @click="$emit('on-' + item.type)"
15
- >
16
- {{ item.name }}
17
- </ListItem>
18
- <IconContainer @click="expandOptions">
19
- <ButtonContainer
20
- v-if="optionsList.length > optionLimit || hasComponent"
21
- name="more_options,_tool_tips"
22
- >
23
- <DotItem />
24
- <DotItem />
25
- <DotItem />
26
- </ButtonContainer>
27
- </IconContainer>
28
- </ListContainer>
29
- <EmptyText v-if="!optionsList.length">
30
- {{ $gettext('no_batch_actions_available') }}
31
- </EmptyText>
32
- <CloseContainer>
33
- <IconContainer @click="$emit('on-close')">
34
- <Icon
35
- color="white"
36
- cursor="pointer"
37
- name="close_for_modals,_tool_tips"
38
- size="14px"
39
- />
40
- </IconContainer>
41
- </CloseContainer>
42
- </BoxContainer>
43
- </PageContainer>
44
- <CenterPageContainer v-else>
3
+ <CenterPageContainer v-if="expanded">
45
4
  <CenterBox>
46
5
  <TitleContainer>
47
- <BoxTitle> {{ numberSelected }} {{ $gettext('selected') }} </BoxTitle>
6
+ <BoxTitle> {{ numberSelected }} {{ selectedText }} </BoxTitle>
48
7
  <IconContainer @click="$emit('on-close')">
49
8
  <Icon
50
9
  color="white"
@@ -62,7 +21,7 @@
62
21
  v-for="item in expandedOptions"
63
22
  :key="item.type"
64
23
  :disabled="item.disabled || false"
65
- :hasComponent="!!item?.component"
24
+ :has-component="!!item?.component"
66
25
  :hover-color="item.hoverColor"
67
26
  @click="
68
27
  !item?.component && !item.disabled && $emit('on-' + item.type)
@@ -70,7 +29,8 @@
70
29
  >
71
30
  <ListItemWrapper
72
31
  v-if="item?.component"
73
- :hasComponent="!!item?.component"
32
+ :has-component="!!item?.component"
33
+ test-data-id="expanded_list_item"
74
34
  @click="!item.disabled && toggleElement(item.type)"
75
35
  >
76
36
  <ListItemTitle>
@@ -99,6 +59,48 @@
99
59
  </ExpandedList>
100
60
  </CenterBox>
101
61
  </CenterPageContainer>
62
+ <PageContainer v-else>
63
+ <BoxContainer>
64
+ <SelectedContainer>
65
+ {{ numberSelected }} {{ selectedText }}
66
+ </SelectedContainer>
67
+ <ListContainer v-if="optionsList.length">
68
+ <ListItem
69
+ v-for="item in limitedOptions"
70
+ :key="item.type"
71
+ :disabled="item.disabled || false"
72
+ :hover-color="item.hoverColor"
73
+ @click="$emit('on-' + item.type)"
74
+ >
75
+ {{ item.name }}
76
+ </ListItem>
77
+ <IconContainer
78
+ v-if="optionsList.length > optionLimit || hasComponent"
79
+ test-data-id="more_actions_button_wrapper"
80
+ @click="expandOptions"
81
+ >
82
+ <ButtonContainer name="more_options,_tool_tips">
83
+ <DotItem />
84
+ <DotItem />
85
+ <DotItem />
86
+ </ButtonContainer>
87
+ </IconContainer>
88
+ </ListContainer>
89
+ <EmptyText v-else test-data-id="no_bulk_actions">
90
+ {{ noBulkActionsText }}
91
+ </EmptyText>
92
+ <CloseContainer>
93
+ <IconContainer @click="$emit('on-close')">
94
+ <Icon
95
+ color="white"
96
+ cursor="pointer"
97
+ name="close_for_modals,_tool_tips"
98
+ size="14px"
99
+ />
100
+ </IconContainer>
101
+ </CloseContainer>
102
+ </BoxContainer>
103
+ </PageContainer>
102
104
  </PageWrapper>
103
105
  </template>
104
106
 
@@ -173,8 +175,8 @@
173
175
  `
174
176
 
175
177
  const OptionsContainer = styled.div`
176
- position: fixed;
177
- right: -252px;
178
+ position: absolute;
179
+ left: 101%;
178
180
  background-color: ${(props) => props.theme.colors.black};
179
181
  border-radius: 4px;
180
182
  padding: 15px;
@@ -378,12 +380,21 @@
378
380
  optionsList: {
379
381
  type: Array,
380
382
  required: true,
383
+ default: () => [],
381
384
  },
382
385
  numberSelected: {
383
386
  type: Number,
384
387
  required: true,
385
388
  default: 0,
386
389
  },
390
+ selectedLabel: {
391
+ type: String,
392
+ default: null,
393
+ },
394
+ noBulkActionsLabel: {
395
+ type: String,
396
+ default: null,
397
+ },
387
398
  },
388
399
  data() {
389
400
  return {
@@ -401,6 +412,16 @@
401
412
  limitedOptions() {
402
413
  return this.expandedOptions.filter((option) => !option.component)
403
414
  },
415
+ selectedText() {
416
+ //work around for storybook not finding the $gettext function
417
+ return this.selectedLabel || this.$gettext('selected')
418
+ },
419
+ noBulkActionsText() {
420
+ //work around for storybook not finding the $gettext function
421
+ return (
422
+ this.noBulkActionsLabel || this.$gettext('no_batch_actions_available')
423
+ )
424
+ },
404
425
  },
405
426
  watch: {
406
427
  optionsList() {
@@ -415,7 +436,7 @@
415
436
  this.expandedOptions = [...this.optionsList]
416
437
  .map((option, index) => {
417
438
  const currentOption = this.expandedOptions[index]
418
- const isOpen = !!currentOption ? currentOption.open : false
439
+ const isOpen = currentOption ? currentOption.open : false
419
440
 
420
441
  return { ...option, open: isOpen }
421
442
  })
@@ -0,0 +1,176 @@
1
+ /* eslint-disable */
2
+ import { mount } from '@vue/test-utils'
3
+ import RCSelectedOptions from '@/components/selectedOptions'
4
+ import theme from '@/assets/theme'
5
+
6
+ jest.mock('@/components/icon/iconCache.mjs', () => ({
7
+ // need to mock this due to how jest handles import.meta
8
+ fetchIcon: jest.fn(() => Promise.resolve('close_for_modals,_tool_tips.svg')),
9
+ }))
10
+
11
+ describe('RCSelectedOptions.vue', () => {
12
+ const simpleOptionsProps = {
13
+ optionLimit: 4,
14
+ numberSelected: 2,
15
+ selectedLabel: 'selected',
16
+ noBulkActionsLabel: 'No bulk actions available',
17
+ optionsList: [
18
+ {
19
+ type: 'close',
20
+ name: 'Close',
21
+ },
22
+ {
23
+ type: 'delete',
24
+ name: 'Delete',
25
+ hoverColor: 'red',
26
+ },
27
+ ],
28
+ }
29
+
30
+ it('selected options are rendered with correct options', () => {
31
+ const wrapper = mount(RCSelectedOptions, {
32
+ props: simpleOptionsProps,
33
+ global: {
34
+ provide: {
35
+ theme,
36
+ },
37
+ },
38
+ })
39
+
40
+ const selectedOptions = wrapper.findComponent(RCSelectedOptions)
41
+ expect(selectedOptions.exists()).toBe(true)
42
+ })
43
+
44
+ it('should display "No bulk actions available" if there are no options', () => {
45
+ const wrapper = mount(RCSelectedOptions, {
46
+ props: {
47
+ ...simpleOptionsProps,
48
+ optionsList: [],
49
+ },
50
+ global: {
51
+ provide: {
52
+ theme,
53
+ },
54
+ },
55
+ })
56
+
57
+ const selectedOptions = wrapper.findComponent(RCSelectedOptions)
58
+ expect(selectedOptions.exists()).toBe(true)
59
+
60
+ const noBulkActions = selectedOptions.find(
61
+ '[test-data-id="no_bulk_actions"]'
62
+ )
63
+ expect(noBulkActions.exists()).toBe(true)
64
+ })
65
+
66
+ it('should not display "•••" option if it is less than the limit of 4', () => {
67
+ const wrapper = mount(RCSelectedOptions, {
68
+ props: simpleOptionsProps,
69
+ global: {
70
+ provide: {
71
+ theme,
72
+ },
73
+ },
74
+ })
75
+
76
+ const selectedOptions = wrapper.findComponent(RCSelectedOptions)
77
+ expect(selectedOptions.exists()).toBe(true)
78
+
79
+ //since we have 2 options, and the limit is 4, we should not see "•••" button
80
+ const moreActionsButton = selectedOptions.find(
81
+ '[test-data-id="more_actions_button_wrapper"]'
82
+ )
83
+ expect(moreActionsButton.exists()).toBe(false)
84
+ })
85
+
86
+ it('should display "•••" option if it is more than the limit of 4 or if there is a component parameter on the options', () => {
87
+ const wrapper = mount(RCSelectedOptions, {
88
+ props: {
89
+ ...simpleOptionsProps,
90
+ optionsList: [
91
+ {
92
+ type: 'close',
93
+ name: 'Close',
94
+ },
95
+ {
96
+ type: 'delete',
97
+ name: 'Delete',
98
+ component: 'set_supplier',
99
+ },
100
+ ],
101
+ },
102
+ global: {
103
+ provide: {
104
+ theme,
105
+ },
106
+ },
107
+ })
108
+
109
+ const selectedOptions = wrapper.findComponent(RCSelectedOptions)
110
+ expect(selectedOptions.exists()).toBe(true)
111
+
112
+ //since we a component parameter, we should see "•••" button
113
+ const moreActionsButton = selectedOptions.find(
114
+ '[test-data-id="more_actions_button_wrapper"]'
115
+ )
116
+ expect(moreActionsButton.exists()).toBe(true)
117
+ })
118
+ it("should display the named slot content when the 'component' parameter is passed", async () => {
119
+ const wrapper = mount(RCSelectedOptions, {
120
+ props: {
121
+ ...simpleOptionsProps,
122
+ optionsList: [
123
+ {
124
+ type: 'close',
125
+ name: 'Close',
126
+ },
127
+ {
128
+ type: 'delete',
129
+ name: 'Delete',
130
+ component: 'set_supplier',
131
+ },
132
+ ],
133
+ },
134
+ global: {
135
+ provide: {
136
+ theme,
137
+ },
138
+ },
139
+ slots: {
140
+ set_supplier: '<div data-id="set_supplier">set_supplier</div>',
141
+ },
142
+ })
143
+
144
+ const selectedOptions = wrapper.findComponent(RCSelectedOptions)
145
+ expect(selectedOptions.exists()).toBe(true)
146
+
147
+ //since we a component parameter, we should see "•••" button
148
+ const moreActionsButton = selectedOptions.find(
149
+ '[test-data-id="more_actions_button_wrapper"]'
150
+ )
151
+ expect(moreActionsButton.exists()).toBe(true)
152
+
153
+ //click the more actions button
154
+ moreActionsButton.trigger('click')
155
+ selectedOptions.vm.expanded = true
156
+ selectedOptions.vm.expandedOptions = selectedOptions.props().optionsList
157
+ expect(selectedOptions.vm.expanded).toBe(true)
158
+
159
+ await wrapper.vm.$nextTick()
160
+
161
+ //toggle the element with the component parameter
162
+ const expandedListItems = selectedOptions.findAll(
163
+ '[test-data-id="expanded_list_item"]'
164
+ )
165
+
166
+ //there should be only one since we have only one option with the component parameter
167
+ expect(expandedListItems.length).toBe(1)
168
+ expandedListItems[0].trigger('click')
169
+
170
+ await wrapper.vm.$nextTick()
171
+
172
+ //check if the named slot content is displayed
173
+ const setSupplierSlot = wrapper.find('[data-id="set_supplier"]')
174
+ expect(setSupplierSlot.exists()).toBe(true)
175
+ })
176
+ })
@@ -0,0 +1,155 @@
1
+ import SelectedOptions from './index.vue'
2
+
3
+ export default {
4
+ title: 'Components/SelectedOptions',
5
+ component: SelectedOptions,
6
+ tags: ['autodocs'],
7
+ // argTypes: {}
8
+ }
9
+
10
+ // How to use in your template
11
+ // import SelectedOptions from "@eturnity/eturnity_reusable_components/src/components/selectedOptions"
12
+ //
13
+ // optionsList = [
14
+ // {
15
+ // type: 'close',
16
+ // name: 'Close'
17
+ // },
18
+ // {
19
+ // type: 'export',
20
+ // name: 'Export'
21
+ // ...
22
+ // add component parameter if we were passing a component to the selected options (see below)
23
+ // component: 'set_supplier'
24
+ // },
25
+ // {
26
+ // type: 'delete',
27
+ // name: 'Delete',
28
+ // hoverColor: 'red' // default is green
29
+ // }
30
+ // ]
31
+ //
32
+ // @on-${type}="function" should $emit the callback for the 'type' in the optionsList
33
+ //
34
+ // <selected-options
35
+ // :numberSelected="numberSelected"
36
+ // :optionsList="optionsList"
37
+ // @on-close="onCloseFunction()"
38
+ // @on-export="function()" @on-delete="function()"
39
+ // >
40
+ // add any custom components here that you want to pass to the expanded options
41
+ // <template v-slot:set_supplier>
42
+ // <CustomSelectComponent
43
+ // :option-list="suppliers"
44
+ // @set-supplier="checkboxBulkActions('setSupplier', $event)"
45
+ // />
46
+ // </template>
47
+ // </SelectedOptions>
48
+
49
+ export const Default = {
50
+ render: (args) => ({
51
+ components: { SelectedOptions },
52
+ setup() {
53
+ return { args }
54
+ },
55
+ template: '<SelectedOptions v-bind="args" />',
56
+ }),
57
+ args: {
58
+ optionLimit: 4,
59
+ selectedLabel: 'selected',
60
+ noBulkActionsLabel: 'No bulk actions available',
61
+
62
+ //selected options count, in this case 5 options are selected
63
+ numberSelected: 5,
64
+
65
+ //show overlay
66
+ showOverlay: true,
67
+
68
+ //expanded options, this will display list of actions in the middle of the screen
69
+ expanded: false,
70
+ optionsList: [
71
+ {
72
+ type: 'export',
73
+ name: 'Export',
74
+ },
75
+ {
76
+ type: 'export_page',
77
+ name: 'Export Page',
78
+ },
79
+ ],
80
+ expandedOptions: [],
81
+ },
82
+ }
83
+
84
+ export const Expanded = {
85
+ render: (args) => ({
86
+ components: { SelectedOptions },
87
+ setup() {
88
+ return { args }
89
+ },
90
+ template: `
91
+ <SelectedOptions v-bind="args">
92
+ <template v-slot:set_supplier>
93
+ <div>supplier</div>
94
+ </template>
95
+ </SelectedOptions>
96
+ `,
97
+ }),
98
+ args: {
99
+ ...Default.args,
100
+ //expanded options, this will display list of actions in the middle of the screen
101
+ expanded: true,
102
+
103
+ //optionsList, to be displayed when expanded is false and this will be filtered based on the optionLimit
104
+ optionsList: [
105
+ {
106
+ type: 'export',
107
+ name: 'Export',
108
+ },
109
+ {
110
+ type: 'export_page',
111
+ name: 'Export Page',
112
+ },
113
+ {
114
+ type: 'export_all',
115
+ name: 'Export All',
116
+ },
117
+ {
118
+ type: 'export_row',
119
+ name: 'Export Row',
120
+ },
121
+ {
122
+ type: 'set_supplier',
123
+ name: 'Set Supplier',
124
+ // add component parameter if we were passing a component to the selected options
125
+ component: 'set_supplier',
126
+ },
127
+ ],
128
+
129
+ //duplicate of optionsList, to be displayed when expanded is true
130
+ expandedOptions: [
131
+ {
132
+ type: 'export',
133
+ name: 'Export',
134
+ },
135
+ {
136
+ type: 'export_page',
137
+ name: 'Export Page',
138
+ },
139
+ {
140
+ type: 'export_all',
141
+ name: 'Export All',
142
+ },
143
+ {
144
+ type: 'export_row',
145
+ name: 'Export Row',
146
+ },
147
+ {
148
+ type: 'set_supplier',
149
+ name: 'Set Supplier',
150
+ // add component parameter if we were passing a component to the selected options
151
+ component: 'set_supplier',
152
+ },
153
+ ],
154
+ },
155
+ }