@rancher/shell 2.0.0 → 2.0.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.
Files changed (73) hide show
  1. package/assets/translations/en-us.yaml +18 -3
  2. package/components/AlertTable.vue +17 -7
  3. package/components/GrafanaDashboard.vue +6 -4
  4. package/components/PromptRemove.vue +1 -0
  5. package/components/form/KeyValue.vue +1 -0
  6. package/components/form/Taints.vue +13 -7
  7. package/components/form/__tests__/Taints.test.ts +70 -0
  8. package/components/nav/Header.vue +1 -1
  9. package/components/nav/TopLevelMenu.vue +1 -4
  10. package/config/product/auth.js +1 -1
  11. package/config/router/navigation-guards/i18n.js +13 -0
  12. package/config/router/navigation-guards/index.js +2 -1
  13. package/creators/app/app.package.json +2 -1
  14. package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +42 -0
  15. package/detail/provisioning.cattle.io.cluster.vue +4 -4
  16. package/dialog/DeactivateDriverDialog.vue +30 -11
  17. package/edit/auth/__tests__/oidc.test.ts +2 -2
  18. package/edit/token.vue +2 -1
  19. package/initialize/entry-helpers.js +10 -13
  20. package/list/management.cattle.io.feature.vue +4 -2
  21. package/middleware/authenticated.js +0 -19
  22. package/mixins/auth-config.js +1 -1
  23. package/models/driver.js +3 -2
  24. package/models/kontainerdriver.js +30 -13
  25. package/models/management.cattle.io.authconfig.js +2 -2
  26. package/models/nodedriver.js +30 -13
  27. package/package.json +3 -2
  28. package/pages/c/_cluster/apps/charts/install.vue +3 -2
  29. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +0 -3
  30. package/pages/c/_cluster/manager/drivers/nodeDriver/index.vue +1 -4
  31. package/pages/c/_cluster/uiplugins/InstallDialog.vue +2 -1
  32. package/promptRemove/pod.vue +15 -7
  33. package/scripts/publish-shell.sh +1 -0
  34. package/store/auth.js +1 -1
  35. package/store/index.js +1 -1
  36. package/utils/__tests__/kontainer.test.ts +89 -1
  37. package/utils/auth.js +1 -1
  38. package/utils/kontainer.ts +5 -1
  39. package/utils/version.js +2 -1
  40. package/rancher-components/components/Accordion/Accordion.test.ts +0 -45
  41. package/rancher-components/components/Accordion/Accordion.vue +0 -86
  42. package/rancher-components/components/Accordion/index.ts +0 -1
  43. package/rancher-components/components/BadgeState/BadgeState.test.ts +0 -12
  44. package/rancher-components/components/BadgeState/BadgeState.vue +0 -111
  45. package/rancher-components/components/BadgeState/index.ts +0 -1
  46. package/rancher-components/components/Banner/Banner.test.ts +0 -59
  47. package/rancher-components/components/Banner/Banner.vue +0 -244
  48. package/rancher-components/components/Banner/index.ts +0 -1
  49. package/rancher-components/components/Card/Card.test.ts +0 -37
  50. package/rancher-components/components/Card/Card.vue +0 -167
  51. package/rancher-components/components/Card/index.ts +0 -1
  52. package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +0 -68
  53. package/rancher-components/components/Form/Checkbox/Checkbox.vue +0 -421
  54. package/rancher-components/components/Form/Checkbox/index.ts +0 -1
  55. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +0 -40
  56. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +0 -402
  57. package/rancher-components/components/Form/LabeledInput/index.ts +0 -1
  58. package/rancher-components/components/Form/Radio/RadioButton.test.ts +0 -33
  59. package/rancher-components/components/Form/Radio/RadioButton.vue +0 -293
  60. package/rancher-components/components/Form/Radio/RadioGroup.test.ts +0 -30
  61. package/rancher-components/components/Form/Radio/RadioGroup.vue +0 -259
  62. package/rancher-components/components/Form/Radio/index.ts +0 -2
  63. package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +0 -172
  64. package/rancher-components/components/Form/TextArea/index.ts +0 -1
  65. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +0 -94
  66. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +0 -152
  67. package/rancher-components/components/Form/ToggleSwitch/index.ts +0 -1
  68. package/rancher-components/components/Form/index.ts +0 -5
  69. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +0 -156
  70. package/rancher-components/components/LabeledTooltip/index.ts +0 -1
  71. package/rancher-components/components/StringList/StringList.test.ts +0 -754
  72. package/rancher-components/components/StringList/StringList.vue +0 -650
  73. package/rancher-components/components/StringList/index.ts +0 -1
@@ -8,19 +8,21 @@ export default class KontainerDriver extends Driver {
8
8
  get _availableActions() {
9
9
  const out = [
10
10
  {
11
- action: 'activate',
12
- label: 'Activate',
13
- icon: 'icon icon-play',
14
- bulkable: true,
15
- enabled: !!this.links.update && !this.active
11
+ action: 'activate',
12
+ label: this.t('action.activate'),
13
+ icon: 'icon icon-play',
14
+ bulkable: true,
15
+ bulkAction: 'activateBulk',
16
+ enabled: !!this.links.update && !this.active
16
17
  },
17
18
  {
18
- action: 'deactivate',
19
- label: 'Deactivate',
20
- icon: 'icon icon-pause',
21
- bulkable: true,
22
- enabled: !!this.links.update && !!this.active,
23
- weight: -1
19
+ action: 'deactivate',
20
+ label: this.t('action.deactivate'),
21
+ icon: 'icon icon-pause',
22
+ bulkable: true,
23
+ bulkAction: 'deactivateBulk',
24
+ enabled: !!this.links.update && !!this.active,
25
+ weight: -1
24
26
  },
25
27
  { divider: true },
26
28
  {
@@ -52,9 +54,16 @@ export default class KontainerDriver extends Driver {
52
54
  return out;
53
55
  }
54
56
 
55
- deactivate() {
57
+ deactivate(resources = [this]) {
58
+ this.$dispatch('promptModal', {
59
+ componentProps: { drivers: resources, driverType: 'kontainerDrivers' },
60
+ component: 'DeactivateDriverDialog'
61
+ });
62
+ }
63
+
64
+ deactivateBulk(resources) {
56
65
  this.$dispatch('promptModal', {
57
- componentProps: { url: `v3/kontainerDrivers/${ escape(this.id) }?action=deactivate`, name: this.nameDisplay },
66
+ componentProps: { drivers: resources, driverType: 'kontainerDrivers' },
58
67
  component: 'DeactivateDriverDialog'
59
68
  });
60
69
  }
@@ -65,4 +74,12 @@ export default class KontainerDriver extends Driver {
65
74
  method: 'post',
66
75
  }, { root: true });
67
76
  }
77
+
78
+ async activateBulk(resources) {
79
+ await Promise.all(resources.map((resource) => this.$dispatch('rancher/request', {
80
+ url: `v3/kontainerDrivers/${ escape(resource.id) }?action=activate`,
81
+ method: 'post',
82
+ }, { root: true }
83
+ )));
84
+ }
68
85
  }
@@ -15,10 +15,10 @@ export const configType = {
15
15
  local: '',
16
16
  github: 'oauth',
17
17
  keycloakoidc: 'oidc',
18
- oidc: 'oidc',
18
+ genericoidc: 'oidc',
19
19
  };
20
20
 
21
- const imageOverrides = { keycloakoidc: 'keycloak', oidc: 'openid' };
21
+ const imageOverrides = { keycloakoidc: 'keycloak', genericoidc: 'openid' };
22
22
 
23
23
  export default class AuthConfig extends SteveModel {
24
24
  get _availableActions() {
@@ -8,19 +8,21 @@ export default class NodeDriver extends Driver {
8
8
  get _availableActions() {
9
9
  const out = [
10
10
  {
11
- action: 'activate',
12
- label: 'Activate',
13
- icon: 'icon icon-play',
14
- bulkable: true,
15
- enabled: !!this.actions.activate && this.state === 'inactive',
11
+ action: 'activate',
12
+ label: this.t('action.activate'),
13
+ icon: 'icon icon-play',
14
+ bulkable: true,
15
+ bulkAction: 'activateBulk',
16
+ enabled: !!this.actions.activate && this.state === 'inactive',
16
17
  },
17
18
  {
18
- action: 'deactivate',
19
- label: 'Deactivate',
20
- icon: 'icon icon-pause',
21
- bulkable: true,
22
- enabled: !!this.actions.deactivate && this.state === 'active',
23
- weight: -1,
19
+ action: 'deactivate',
20
+ label: this.t('action.deactivate'),
21
+ icon: 'icon icon-pause',
22
+ bulkable: true,
23
+ bulkAction: 'deactivateBulk',
24
+ enabled: !!this.actions.deactivate && this.state === 'active',
25
+ weight: -1,
24
26
  },
25
27
  { divider: true },
26
28
  {
@@ -52,9 +54,16 @@ export default class NodeDriver extends Driver {
52
54
  return out;
53
55
  }
54
56
 
55
- deactivate() {
57
+ deactivate(resources = [this]) {
58
+ this.$dispatch('promptModal', {
59
+ componentProps: { drivers: resources, driverType: 'nodeDrivers' },
60
+ component: 'DeactivateDriverDialog'
61
+ });
62
+ }
63
+
64
+ deactivateBulk(resources) {
56
65
  this.$dispatch('promptModal', {
57
- componentProps: { url: `v3/nodeDrivers/${ escape(this.id) }?action=deactivate`, name: this.nameDisplay },
66
+ componentProps: { drivers: resources, driverType: 'nodeDrivers' },
58
67
  component: 'DeactivateDriverDialog'
59
68
  });
60
69
  }
@@ -65,4 +74,12 @@ export default class NodeDriver extends Driver {
65
74
  method: 'post',
66
75
  }, { root: true });
67
76
  }
77
+
78
+ async activateBulk(resources) {
79
+ await Promise.all(resources.map((resource) => this.$dispatch('rancher/request', {
80
+ url: `v3/nodeDrivers/${ escape(resource.id) }?action=activate`,
81
+ method: 'post',
82
+ }, { root: true }
83
+ )));
84
+ }
68
85
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -153,7 +153,8 @@
153
153
  "nth-check": ">=2.0.1",
154
154
  "follow-redirects": ">=1.14.7",
155
155
  "merge": ">=2.1.1",
156
- "semver": ">=7.5.2"
156
+ "semver": ">=7.5.2",
157
+ "glob": "7.2.3"
157
158
  },
158
159
  "nyc": {
159
160
  "extension": [
@@ -37,6 +37,7 @@ import { findBy, insertAt } from '@shell/utils/array';
37
37
  import Vue from 'vue';
38
38
  import { saferDump } from '@shell/utils/create-yaml';
39
39
  import { LINUX, WINDOWS } from '@shell/store/catalog';
40
+ import { SETTING } from '@shell/config/settings';
40
41
 
41
42
  const VALUES_STATE = {
42
43
  FORM: 'FORM',
@@ -126,7 +127,7 @@ export default {
126
127
  try {
127
128
  this.serverUrlSetting = await this.$store.dispatch('management/find', {
128
129
  type: MANAGEMENT.SETTING,
129
- id: 'server-url'
130
+ id: SETTING.SERVER_URL,
130
131
  });
131
132
  } catch (e) {
132
133
  console.error('Unable to fetch `server-url` setting: ', e); // eslint-disable-line no-console
@@ -888,7 +889,7 @@ export default {
888
889
  // runtime will pull images from docker.io.
889
890
  const globalRegistry = await this.$store.dispatch('management/find', {
890
891
  type: MANAGEMENT.SETTING,
891
- id: 'system-default-registry'
892
+ id: SETTING.SYSTEM_DEFAULT_REGISTRY,
892
893
  });
893
894
 
894
895
  return globalRegistry.value;
@@ -44,9 +44,6 @@ export default {
44
44
  buttonDone(false);
45
45
  }
46
46
  }
47
- },
48
- mounted() {
49
- window.c = this;
50
47
  }
51
48
  };
52
49
  </script>
@@ -26,10 +26,7 @@ export default {
26
26
  rows() {
27
27
  return this.allDrivers || [];
28
28
  },
29
- },
30
- mounted() {
31
- window.c = this;
32
- },
29
+ }
33
30
  };
34
31
  </script>
35
32
 
@@ -6,6 +6,7 @@ import { CATALOG, MANAGEMENT } from '@shell/config/types';
6
6
  import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
7
7
  import { UI_PLUGIN_NAMESPACE } from '@shell/config/uiplugins';
8
8
  import Banner from '@components/Banner/Banner.vue';
9
+ import { SETTING } from '@shell/config/settings';
9
10
 
10
11
  // Note: This dialog handles installation and update of a plugin
11
12
 
@@ -20,7 +21,7 @@ export default {
20
21
  async fetch() {
21
22
  this.defaultRegistrySetting = await this.$store.dispatch('management/find', {
22
23
  type: MANAGEMENT.SETTING,
23
- id: 'system-default-registry'
24
+ id: SETTING.SYSTEM_DEFAULT_REGISTRY,
24
25
  });
25
26
  },
26
27
 
@@ -30,6 +30,16 @@ export default {
30
30
  type: {
31
31
  type: String,
32
32
  required: true
33
+ },
34
+
35
+ close: {
36
+ type: Function,
37
+ required: true
38
+ },
39
+
40
+ doneLocation: {
41
+ type: Object,
42
+ default: () => {}
33
43
  }
34
44
  },
35
45
 
@@ -69,23 +79,21 @@ export default {
69
79
 
70
80
  methods: {
71
81
  async remove(confirm) {
72
- const parentComponent = this.$parent.$parent.$parent;
73
-
74
82
  let goTo;
75
83
 
76
- if (parentComponent.doneLocation) {
84
+ if (this.doneLocation) {
77
85
  // doneLocation will recompute to undefined when delete request completes
78
- goTo = { ...parentComponent.doneLocation };
86
+ goTo = { ...this.doneLocation };
79
87
  }
80
88
 
81
89
  try {
82
90
  await Promise.all(this.value.map((resource) => this.removePod(resource)));
83
91
  if ( goTo && !isEmpty(goTo) ) {
84
- parentComponent.currentRouter.push(goTo);
92
+ this.value?.[0]?.currentRouter().push(goTo);
85
93
  }
86
- parentComponent.close();
94
+ this.close();
87
95
  } catch (err) {
88
- parentComponent.error = err;
96
+ this.$emit('errors', err);
89
97
  confirm(false);
90
98
  }
91
99
  },
@@ -67,6 +67,7 @@ function publish() {
67
67
  # For now, copy the rancher components into the shell and ship them with it
68
68
  if [ "$NAME" == "Shell" ]; then
69
69
  echo "Adding Rancher Components"
70
+ rm -rf ./rancher-components
70
71
  cp -R ${BASE_DIR}/pkg/rancher-components/src/components ./rancher-components/
71
72
  fi
72
73
 
package/store/auth.js CHANGED
@@ -13,7 +13,7 @@ export const BASE_SCOPES = {
13
13
  googleoauth: ['openid profile email'],
14
14
  azuread: [],
15
15
  keycloakoidc: ['openid profile email'],
16
- oidc: ['openid profile email'],
16
+ genericoidc: ['openid profile email'],
17
17
  };
18
18
 
19
19
  const KEY = 'rc_nonce';
package/store/index.js CHANGED
@@ -594,7 +594,7 @@ export const getters = {
594
594
  },
595
595
 
596
596
  releaseNotesUrl(state, getters) {
597
- const version = getters['management/byId'](MANAGEMENT.SETTING, 'server-version')?.value;
597
+ const version = getters['management/byId'](MANAGEMENT.SETTING, SETTING.VERSION_RANCHER)?.value;
598
598
 
599
599
  const base = 'https://github.com/rancher/rancher/releases';
600
600
 
@@ -1,4 +1,4 @@
1
- import { diffUpstreamSpec } from '@shell/utils/kontainer';
1
+ import { diffUpstreamSpec, syncUpstreamConfig } from '@shell/utils/kontainer';
2
2
 
3
3
  describe('fx: diffUpstreamSpec', () => {
4
4
  it.each([
@@ -90,3 +90,91 @@ describe('fx: diffUpstreamSpec', () => {
90
90
  expect(diffUpstreamSpec(upstream, local)).toStrictEqual(diff);
91
91
  });
92
92
  });
93
+
94
+ describe('fx: syncUpstreamSpec', () => {
95
+ it('should set any fields defined in upstream spec and not local spec', () => {
96
+ const upstream = {
97
+ string: 'def',
98
+ 'other-string': '123',
99
+ alreadySet: 'abc',
100
+ alreadySetArray: [2, 3, 4],
101
+ alreadySetBooleanFalse: false,
102
+ alreadySetBooleanTrue: true
103
+ };
104
+ const local = {
105
+ alreadySet: 'def',
106
+ alreadySetArray: [1, 2, 3],
107
+ alreadySetBooleanFalse: false,
108
+ alreadySetBooleanTrue: true
109
+ };
110
+
111
+ const expected = {
112
+ string: 'def',
113
+ 'other-string': '123',
114
+ alreadySet: 'def',
115
+ alreadySetArray: [1, 2, 3],
116
+ alreadySetBooleanFalse: false,
117
+ alreadySetBooleanTrue: true
118
+ };
119
+
120
+ const testCluster = { eksConfig: local, eksStatus: { upstreamSpec: upstream } };
121
+
122
+ syncUpstreamConfig( 'eks', testCluster);
123
+
124
+ expect(testCluster.eksConfig).toStrictEqual(expected);
125
+ });
126
+
127
+ it('should not set empty objects or arrays from upstream spec', () => {
128
+ const upstream = {
129
+ emptyArray: [],
130
+ emptyObject: {},
131
+ nonEmptyArray: [1, 2, 3],
132
+ nonEmptyObject: { foo: 'bar' },
133
+ alreadySet: 'abc',
134
+ alreadySetArray: [2, 3, 4],
135
+ };
136
+ const local = {
137
+ alreadySet: 'def',
138
+ alreadySetArray: [1, 2, 3],
139
+ };
140
+
141
+ const expected = {
142
+ nonEmptyArray: [1, 2, 3],
143
+ nonEmptyObject: { foo: 'bar' },
144
+ alreadySet: 'def',
145
+ alreadySetArray: [1, 2, 3],
146
+ };
147
+
148
+ const testCluster = { eksConfig: local, eksStatus: { upstreamSpec: upstream } };
149
+
150
+ syncUpstreamConfig( 'eks', testCluster);
151
+
152
+ expect(testCluster.eksConfig).toStrictEqual(expected);
153
+ });
154
+
155
+ it('should not overwrite boolean values explicitly set false', () => {
156
+ const upstream = {
157
+ falseBoolean: false,
158
+ trueBoolean: true,
159
+ alreadySetBooleanFalse: true,
160
+ alreadySetBooleanTrue: false
161
+ };
162
+ const local = {
163
+ alreadySetBooleanFalse: false,
164
+ alreadySetBooleanTrue: true
165
+ };
166
+
167
+ const expected = {
168
+ falseBoolean: false,
169
+ trueBoolean: true,
170
+ alreadySetBooleanFalse: false,
171
+ alreadySetBooleanTrue: true
172
+ };
173
+
174
+ const testCluster = { eksConfig: local, eksStatus: { upstreamSpec: upstream } };
175
+
176
+ syncUpstreamConfig( 'eks', testCluster);
177
+
178
+ expect(testCluster.eksConfig).toStrictEqual(expected);
179
+ });
180
+ });
package/utils/auth.js CHANGED
@@ -71,7 +71,7 @@ export const authProvidersInfo = async(store) => {
71
71
  const nonLocal = rows.filter((x) => x.name !== 'local');
72
72
  const enabled = nonLocal.filter((x) => x.enabled === true );
73
73
 
74
- const supportedNonLocal = nonLocal.filter((x) => x.id !== 'genericoidc');
74
+ const supportedNonLocal = nonLocal.filter((x) => x.id !== 'oidc');
75
75
 
76
76
  const enabledLocation = enabled.length === 1 ? {
77
77
  name: 'c-cluster-auth-config-id',
@@ -17,7 +17,11 @@ export function syncUpstreamConfig(configPrefix: string, normanCluster: {[key: s
17
17
 
18
18
  if (!isEmpty(upstreamConfig)) {
19
19
  Object.keys(upstreamConfig).forEach((key) => {
20
- if (isEmpty(rancherConfig[key]) && !isEmpty(upstreamConfig[key])) {
20
+ if (typeof upstreamConfig[key] === 'object') {
21
+ if (isEmpty(rancherConfig[key]) && !isEmpty(upstreamConfig[key])) {
22
+ set(rancherConfig, key, upstreamConfig[key]);
23
+ }
24
+ } else if ((rancherConfig[key] === null || rancherConfig[key] === undefined) && upstreamConfig[key] !== null && upstreamConfig[key] !== undefined) {
21
25
  set(rancherConfig, key, upstreamConfig[key]);
22
26
  }
23
27
  });
package/utils/version.js CHANGED
@@ -2,6 +2,7 @@ import { sortableNumericSuffix } from '@shell/utils/sort';
2
2
  import semver from 'semver';
3
3
  import { MANAGEMENT } from '@shell/config/types';
4
4
  import { READ_WHATS_NEW, SEEN_WHATS_NEW } from '@shell/store/prefs';
5
+ import { SETTING } from '@shell/config/settings';
5
6
 
6
7
  export function parse(str) {
7
8
  str = `${ str }`;
@@ -82,7 +83,7 @@ export function isDevBuild(version) {
82
83
  }
83
84
 
84
85
  export function getVersionInfo(store) {
85
- const setting = store.getters['management/byId'](MANAGEMENT.SETTING, 'server-version');
86
+ const setting = store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.VERSION_RANCHER);
86
87
  const fullVersion = setting?.value || 'unknown';
87
88
  let displayVersion = fullVersion;
88
89
 
@@ -1,45 +0,0 @@
1
- import { shallowMount } from '@vue/test-utils';
2
- import { Accordion } from './index';
3
-
4
- describe('component: Accordion', () => {
5
- it('is closed initially by default', () => {
6
- const title = 'Test Title';
7
-
8
- const wrapper = shallowMount(Accordion, { propsData: { title } });
9
-
10
- expect(wrapper.find('[data-testid="accordion-body"]').isVisible()).toBe(false);
11
- expect(wrapper.find('[data-testid="accordion-header"]').text()).toBe(title);
12
- });
13
-
14
- it('is opened initially when openInitially prop is true', () => {
15
- const wrapper = shallowMount(Accordion, { propsData: { openInitially: true } });
16
-
17
- expect(wrapper.find('[data-testid="accordion-body"]').isVisible()).toBe(true);
18
- });
19
-
20
- it('when closed, opens when the header is clicked', async() => {
21
- const wrapper = shallowMount(Accordion, { });
22
-
23
- await wrapper.find('[data-testid="accordion-header"]').trigger('click');
24
- expect(wrapper.find('[data-testid="accordion-body"]').isVisible()).toBe(true);
25
- });
26
-
27
- it('when open, closes when the header is clicked', async() => {
28
- const wrapper = shallowMount(Accordion, { propsData: { openInitially: true } });
29
-
30
- await wrapper.find('[data-testid="accordion-header"]').trigger('click');
31
- expect(wrapper.find('[data-testid="accordion-body"]').isVisible()).toBe(false);
32
- });
33
-
34
- it('displays a chevron when closed', async() => {
35
- const wrapper = shallowMount(Accordion, { propsData: { } });
36
-
37
- expect(wrapper.find('[data-testid="accordion-header"] .icon-chevron-up').exists()).toBe(true);
38
- });
39
-
40
- it('displays an inverted chevron when open', async() => {
41
- const wrapper = shallowMount(Accordion, { propsData: { openInitially: true } });
42
-
43
- expect(wrapper.find('[data-testid="accordion-header"] .icon-chevron-down').exists()).toBe(true);
44
- });
45
- });
@@ -1,86 +0,0 @@
1
- <script lang="ts">
2
- import { defineComponent } from 'vue';
3
- import { mapGetters } from 'vuex';
4
-
5
- export default defineComponent({
6
- props: {
7
- title: {
8
- type: String,
9
- default: ''
10
- },
11
-
12
- titleKey: {
13
- type: String,
14
- default: null
15
- },
16
-
17
- openInitially: {
18
- type: Boolean,
19
- default: false
20
- }
21
- },
22
-
23
- data() {
24
- return { isOpen: this.openInitially };
25
- },
26
-
27
- computed: { ...mapGetters({ t: 'i18n/t' }) },
28
-
29
- methods: {
30
- toggle() {
31
- this.isOpen = !this.isOpen;
32
- }
33
- }
34
- });
35
- </script>
36
-
37
- <template>
38
- <div class="accordion-container">
39
- <div
40
- class="accordion-header"
41
- data-testid="accordion-header"
42
- @click="toggle"
43
- >
44
- <i
45
- class="icon text-primary"
46
- :class="{'icon-chevron-down':isOpen, 'icon-chevron-up':!isOpen}"
47
- data-testid="accordion-chevron"
48
- />
49
- <slot name="header">
50
- <h4
51
- data-testid="accordion-title-slot-content"
52
- class="mb-0"
53
- >
54
- {{ titleKey ? t(titleKey) : title }}
55
- </h4>
56
- </slot>
57
- </div>
58
- <div
59
- v-show="isOpen"
60
- class="accordion-body"
61
- data-testid="accordion-body"
62
- >
63
- <slot />
64
- </div>
65
- </div>
66
- </template>
67
-
68
- <style lang="scss" scoped>
69
- .accordion-container {
70
- border: 1px solid var(--border)
71
- }
72
- .accordion-header {
73
- padding: 5px;
74
- display: flex;
75
- align-items: center;
76
- &>*{
77
- padding: 5px 0px 5px 0px;
78
- }
79
- I {
80
- margin: 0px 10px 0px 10px;
81
- }
82
- }
83
- .accordion-body {
84
- padding: 10px;
85
- }
86
- </style>
@@ -1 +0,0 @@
1
- export { default as Accordion } from './Accordion.vue';
@@ -1,12 +0,0 @@
1
- import { shallowMount } from '@vue/test-utils';
2
- import { BadgeState } from './index';
3
-
4
- describe('BadgeState.vue', () => {
5
- it('renders props.msg when passed', () => {
6
- const label = 'Hello, World!';
7
-
8
- const wrapper = shallowMount(BadgeState, { propsData: { label } });
9
-
10
- expect(wrapper.find('span').text()).toMatch(label);
11
- });
12
- });