@rancher/shell 3.0.0-rc.1 → 3.0.0-rc.2

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 (89) hide show
  1. package/assets/styles/base/_variables.scss +1 -0
  2. package/assets/styles/global/_layout.scss +3 -3
  3. package/assets/styles/global/_select.scss +1 -1
  4. package/assets/styles/global/_tooltip.scss +37 -71
  5. package/components/ActionDropdown.vue +9 -13
  6. package/components/ActionMenu.vue +1 -1
  7. package/components/ButtonDropdown.vue +9 -8
  8. package/components/CruResource.vue +4 -2
  9. package/components/InputOrDisplay.vue +21 -33
  10. package/components/LocaleSelector.vue +1 -1
  11. package/components/Questions/__tests__/Boolean.test.ts +1 -2
  12. package/components/Questions/__tests__/Float.test.ts +1 -2
  13. package/components/Questions/__tests__/Int.test.ts +1 -2
  14. package/components/Questions/__tests__/String.test.ts +1 -2
  15. package/components/Questions/__tests__/Yaml.test.ts +1 -1
  16. package/components/Questions/__tests__/utils/questions-defaults.ts +2 -2
  17. package/components/SideNav.vue +3 -3
  18. package/components/__tests__/CodeMirror.test.ts +91 -94
  19. package/components/__tests__/ConsumptionGauge.test.ts +2 -2
  20. package/components/__tests__/NamespaceFilter.test.ts +10 -7
  21. package/components/auth/AllowedPrincipals.vue +2 -2
  22. package/components/auth/RoleDetailEdit.vue +13 -17
  23. package/components/auth/SelectPrincipal.vue +1 -1
  24. package/components/fleet/FleetStatus.vue +13 -14
  25. package/components/form/ArrayList.vue +1 -1
  26. package/components/form/ArrayListGrouped.vue +18 -5
  27. package/components/form/LabeledSelect.vue +16 -11
  28. package/components/form/Select.vue +17 -1
  29. package/components/form/__tests__/Command.test.ts +6 -5
  30. package/components/form/__tests__/Taints.test.ts +9 -9
  31. package/components/formatter/AppSummaryGraph.vue +1 -1
  32. package/components/formatter/FleetSummaryGraph.vue +1 -1
  33. package/components/formatter/MachineSummaryGraph.vue +1 -1
  34. package/components/formatter/Scale.vue +1 -1
  35. package/components/formatter/Weight.vue +1 -1
  36. package/components/nav/Header.vue +31 -14
  37. package/components/nav/NamespaceFilter.vue +1 -1
  38. package/components/nav/TopLevelMenu.vue +7 -6
  39. package/components/nav/WindowManager/ContainerLogs.vue +1 -1
  40. package/components/nav/WindowManager/ContainerShell.vue +7 -2
  41. package/components/nav/WindowManager/__tests__/ContainerLogs.test.ts +195 -192
  42. package/components/nav/WindowManager/__tests__/ContainerShell.test.ts +23 -19
  43. package/core/plugin-routes.ts +42 -29
  44. package/core/plugins-loader.js +2 -0
  45. package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +16 -8
  46. package/detail/helm.cattle.io.projecthelmchart.vue +26 -27
  47. package/edit/__tests__/namespace.test.ts +7 -9
  48. package/edit/__tests__/service.test.ts +14 -2
  49. package/edit/auth/__tests__/azuread.test.ts +10 -11
  50. package/edit/auth/azuread.vue +1 -1
  51. package/edit/fleet.cattle.io.clustergroup.vue +3 -3
  52. package/edit/management.cattle.io.fleetworkspace.vue +3 -3
  53. package/edit/management.cattle.io.node.vue +3 -2
  54. package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +3 -2
  55. package/edit/namespace.vue +3 -1
  56. package/edit/networking.k8s.io.ingress/index.vue +3 -2
  57. package/edit/networking.k8s.io.networkpolicy/index.vue +2 -2
  58. package/edit/node.vue +3 -3
  59. package/edit/persistentvolume/__tests__/persistentvolume.test.ts +9 -4
  60. package/edit/persistentvolume/index.vue +3 -3
  61. package/edit/persistentvolumeclaim.vue +3 -3
  62. package/edit/policy.poddisruptionbudget.vue +3 -3
  63. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +5 -6
  64. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +13 -6
  65. package/edit/provisioning.cattle.io.cluster/rke2.vue +7 -1
  66. package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +6 -7
  67. package/edit/service.vue +2 -2
  68. package/edit/serviceaccount.vue +3 -3
  69. package/edit/storage.k8s.io.storageclass/index.vue +3 -3
  70. package/edit/workload/Job.vue +2 -2
  71. package/edit/workload/__tests__/Job.test.ts +5 -5
  72. package/edit/workload/index.vue +2 -2
  73. package/edit/workload/storage/Mount.vue +7 -4
  74. package/edit/workload/storage/__tests__/Mount.test.ts +6 -2
  75. package/edit/workload/storage/index.vue +10 -23
  76. package/initialize/entry-helpers.js +0 -5
  77. package/mixins/page-actions.js +1 -1
  78. package/package.json +1 -1
  79. package/pages/c/_cluster/istio/index.vue +2 -2
  80. package/pages/c/_cluster/longhorn/__tests__/longhorn.index.test.ts +3 -2
  81. package/pages/c/_cluster/monitoring/index.vue +1 -1
  82. package/pages/c/_cluster/uiplugins/__tests__/AddExtensionRepos.test.ts +7 -29
  83. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -0
  84. package/vue.config.js +409 -391
  85. package/plugins/clean-html-directive.js +0 -10
  86. package/plugins/clean-tooltip-directive.js +0 -9
  87. package/plugins/int-number.js +0 -9
  88. package/plugins/positive-int-number.js +0 -9
  89. package/plugins/trim-whitespace.js +0 -10
@@ -1,96 +1,93 @@
1
- // import { nextTick } from 'vue';
2
- // import { shallowMount, Wrapper } from '@vue/test-utils';
3
- // import CodeMirror from '@shell/components/CodeMirror.vue';
4
- // import { _EDIT, _YAML } from '@shell/config/query-params';
5
-
6
- // // eslint-disable-next-line jest/no-disabled-tests
7
- // describe.skip('component: CodeMirror.vue', () => {
8
- // let wrapper: Wrapper<InstanceType<typeof CodeMirror>>;
9
-
10
- // const options = {
11
- // readOnly: false,
12
- // gutters: [
13
- // 'CodeMirror-lint-markers',
14
- // 'CodeMirror-foldgutter'
15
- // ],
16
- // mode: 'yaml',
17
- // lint: true,
18
- // lineNumbers: true,
19
- // styleActiveLine: true,
20
- // tabSize: 2,
21
- // indentWithTabs: false,
22
- // cursorBlinkRate: 530,
23
- // extraKeys: { 'Ctrl-Space': 'autocomplete' }
24
- // };
25
-
26
- // const mountOptions = {
27
- // propsData: {
28
- // value: '',
29
- // mode: _EDIT,
30
- // options,
31
- // asTextArea: false,
32
- // showKeyMapBox: true,
33
- // },
34
- // mocks: {
35
- // $store: {
36
- // getters: {
37
- // currentStore: () => 'current_store',
38
- // 'current_store/schemaFor': jest.fn(),
39
- // 'current_store/all': jest.fn(),
40
- // 'i18n/t': () => 'Vim',
41
- // 'prefs/get': () => 'Vim',
42
- // 'prefs/theme': jest.fn(),
43
- // }
44
- // },
45
- // $route: { query: { AS: _YAML } },
46
- // $router: { applyQuery: jest.fn() },
47
- // },
48
- // };
49
-
50
- // // eslint-disable-next-line jest/no-disabled-tests
51
- // describe.skip('keyMap info', () => {
52
- // (window as any).__codeMirrorLoader = () => new Promise((resolve) => {
53
- // resolve(true);
54
- // });
55
-
56
- // wrapper = shallowMount(
57
- // CodeMirror,
58
- // mountOptions,
59
- // );
60
-
61
- // it(`should show keyMap preference`, async() => {
62
- // await nextTick();
63
-
64
- // const keyMapBox = wrapper.find('[data-testid="code-mirror-keymap"]');
65
- // const keyboardIcon = keyMapBox.find('.keymap-indicator');
66
- // const closeIcon = keyMapBox.find('.icon-close');
67
-
68
- // expect(keyboardIcon.element).toBeDefined();
69
- // expect(closeIcon.element).toBeDefined();
70
- // });
71
-
72
- // it(`should remove keyMap box`, async() => {
73
- // await nextTick();
74
-
75
- // let keyMapBox = wrapper.find('[data-testid="code-mirror-keymap"]');
76
-
77
- // keyMapBox.trigger('mouseenter');
78
- // await nextTick();
79
-
80
- // const closeIcon = keyMapBox.find('.icon-close');
81
-
82
- // closeIcon.element.click();
83
- // await nextTick();
84
-
85
- // keyMapBox = wrapper.find('[data-testid="code-mirror-keymap"]');
86
-
87
- // expect(keyMapBox.element).toBeUndefined();
88
- // });
89
- // });
90
- // });
91
-
92
- describe.skip('(Vue3 Skip) it must have one test', () => {
93
- it('will pass', () => {
94
- expect(true).toBe(true);
1
+ import { nextTick } from 'vue';
2
+ import { shallowMount, Wrapper } from '@vue/test-utils';
3
+ import CodeMirror from '@shell/components/CodeMirror.vue';
4
+ import { _EDIT, _YAML } from '@shell/config/query-params';
5
+
6
+ // eslint-disable-next-line jest/no-disabled-tests
7
+ describe('component: CodeMirror.vue', () => {
8
+ let wrapper: Wrapper<InstanceType<typeof CodeMirror>>;
9
+
10
+ const options = {
11
+ readOnly: false,
12
+ gutters: [
13
+ 'CodeMirror-lint-markers',
14
+ 'CodeMirror-foldgutter'
15
+ ],
16
+ mode: 'yaml',
17
+ lint: true,
18
+ lineNumbers: true,
19
+ styleActiveLine: true,
20
+ tabSize: 2,
21
+ indentWithTabs: false,
22
+ cursorBlinkRate: 530,
23
+ extraKeys: { 'Ctrl-Space': 'autocomplete' }
24
+ };
25
+
26
+ const mountOptions = {
27
+ propsData: {
28
+ value: '',
29
+ mode: _EDIT,
30
+ options,
31
+ asTextArea: false,
32
+ showKeyMapBox: true,
33
+ },
34
+ global: {
35
+ mocks: {
36
+ $store: {
37
+ getters: {
38
+ currentStore: () => 'current_store',
39
+ 'current_store/schemaFor': jest.fn(),
40
+ 'current_store/all': jest.fn(),
41
+ 'i18n/t': () => 'Vim',
42
+ 'prefs/get': () => 'Vim',
43
+ 'prefs/theme': jest.fn(),
44
+ }
45
+ },
46
+ $route: { query: { AS: _YAML } },
47
+ $router: { applyQuery: jest.fn() },
48
+ },
49
+ }
50
+
51
+ };
52
+
53
+ // eslint-disable-next-line jest/no-disabled-tests
54
+ describe('keyMap info', () => {
55
+ (window as any).__codeMirrorLoader = () => new Promise((resolve) => {
56
+ resolve(true);
57
+ });
58
+
59
+ wrapper = shallowMount(
60
+ CodeMirror,
61
+ mountOptions,
62
+ );
63
+
64
+ it(`should show keyMap preference`, async() => {
65
+ await nextTick();
66
+
67
+ const keyMapBox = wrapper.find('[data-testid="code-mirror-keymap"] .keymap-indicator');
68
+
69
+ const closeIcon = wrapper.find('[data-testid="code-mirror-keymap"] .icon-close');
70
+
71
+ expect(keyMapBox).toBeDefined();
72
+ expect(closeIcon).toBeDefined();
73
+ });
74
+
75
+ it(`should remove keyMap box`, async() => {
76
+ await nextTick();
77
+
78
+ let keyMapBox = wrapper.find('[data-testid="code-mirror-keymap"]');
79
+
80
+ keyMapBox.trigger('mouseenter');
81
+ await nextTick();
82
+
83
+ const closeIcon = keyMapBox.find('.icon-close');
84
+
85
+ closeIcon.element.click();
86
+ await nextTick();
87
+
88
+ keyMapBox = wrapper.find('[data-testid="code-mirror-keymap"]');
89
+
90
+ expect(keyMapBox.exists()).toBe(false);
91
+ });
95
92
  });
96
93
  });
@@ -3,7 +3,7 @@ import ConsumptionGauge from '@shell/components/ConsumptionGauge.vue';
3
3
  import PercentageBar from '@shell/components/PercentageBar.vue';
4
4
 
5
5
  describe('component: ConsumptionGauge', () => {
6
- it.skip('(Vue3 Skip) should render component with the correct data applied', () => {
6
+ it('should render component with the correct data applied', () => {
7
7
  const colorStops = {
8
8
  0: '--success', 30: '--warning', 70: '--error'
9
9
  };
@@ -36,7 +36,7 @@ describe('component: ConsumptionGauge', () => {
36
36
 
37
37
  // checking PercentageBar component render
38
38
  expect(percentageBar.exists()).toBe(true);
39
- expect(Number(percentageBar.attributes().value)).toBe(20);
39
+ expect(percentageBar.props().modelValue).toBe(20);
40
40
  expect(percentageBar.props().colorStops).toStrictEqual(colorStops);
41
41
  });
42
42
 
@@ -17,8 +17,7 @@ describe('component: NamespaceFilter', () => {
17
17
  expect(filter).toBeDefined();
18
18
  });
19
19
 
20
- it.skip('(Vue3 Skip) should display no namespace selection', () => {
21
- const text = 'none';
20
+ it('should display no namespace selection', () => {
22
21
  const wrapper = mount(NamespaceFilter, {
23
22
  computed: {
24
23
  filtered: () => [],
@@ -27,17 +26,17 @@ describe('component: NamespaceFilter', () => {
27
26
  },
28
27
  global: {
29
28
  mocks: {
30
- $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } },
29
+ $store: { getters: { namespaceFilterMode: () => undefined } },
31
30
  $fetchState: { pending: false }
32
31
  },
33
32
  }
34
33
  });
35
34
  const element = wrapper.find(`[data-testid="namespaces-values-none"]`).element.textContent;
36
35
 
37
- expect(element).toContain(text);
36
+ expect(element).toContain('nav.ns.all');
38
37
  });
39
38
 
40
- it.skip('(Vue3 Skip) should display the default namespace', () => {
39
+ it('should display the default namespace', () => {
41
40
  const text = 'special namespace';
42
41
  const wrapper = mount(NamespaceFilter, {
43
42
  computed: {
@@ -47,6 +46,7 @@ describe('component: NamespaceFilter', () => {
47
46
  label: text,
48
47
  kind: 'special',
49
48
  }]),
49
+ isSingleSpecial: () => true
50
50
  },
51
51
  global: { mocks: { $fetchState: { pending: false } } }
52
52
  });
@@ -77,7 +77,7 @@ describe('component: NamespaceFilter', () => {
77
77
  expect(element).toContain(text);
78
78
  });
79
79
 
80
- it.skip('(Vue3 Skip) should display the selected namespace from user preferences if options are available', () => {
80
+ it('should display the selected namespace from user preferences if options are available', () => {
81
81
  const text = 'my preference';
82
82
  const key = 'local';
83
83
  const preferences = {
@@ -97,6 +97,7 @@ describe('component: NamespaceFilter', () => {
97
97
  }],
98
98
  currentProduct: () => undefined,
99
99
  key: () => key,
100
+ value: () => [{ label: text }]
100
101
  },
101
102
  global: {
102
103
  mocks: {
@@ -194,7 +195,7 @@ describe('component: NamespaceFilter', () => {
194
195
  expect(option).toContain(text);
195
196
  });
196
197
 
197
- it.skip('(Vue3 Skip) should set the option as user preference', async() => {
198
+ it('should set the option as user preference', async() => {
198
199
  const text = 'my option';
199
200
  const key = 'my key';
200
201
  const value = {
@@ -205,8 +206,10 @@ describe('component: NamespaceFilter', () => {
205
206
  const action = jest.fn();
206
207
 
207
208
  jest.spyOn(NamespaceFilter.computed.value, 'get').mockReturnValue([]);
209
+
208
210
  const wrapper = mount(NamespaceFilter, {
209
211
  computed: {
212
+ ...NamespaceFilter.computed,
210
213
  options: () => [],
211
214
  currentProduct: () => undefined,
212
215
  key: () => key,
@@ -4,7 +4,7 @@ import ArrayList from '@shell/components/form/ArrayList';
4
4
  import Principal from '@shell/components/auth/Principal';
5
5
  import SelectPrincipal from '@shell/components/auth/SelectPrincipal';
6
6
  import { _EDIT } from '@shell/config/query-params';
7
- import { addObject } from '@shell/utils/array';
7
+ import uniq from 'lodash/uniq';
8
8
 
9
9
  export default {
10
10
  components: {
@@ -56,7 +56,7 @@ export default {
56
56
 
57
57
  methods: {
58
58
  addPrincipal(id) {
59
- addObject(this.authConfig.allowedPrincipalIds, id);
59
+ this.authConfig.allowedPrincipalIds = uniq([...this.authConfig.allowedPrincipalIds, id]);
60
60
  },
61
61
  }
62
62
  };
@@ -16,6 +16,7 @@ import SortableTable from '@shell/components/SortableTable';
16
16
  import { _CLONE, _DETAIL } from '@shell/config/query-params';
17
17
  import { SCOPED_RESOURCES, SCOPED_RESOURCE_GROUPS } from '@shell/config/roles';
18
18
  import { Banner } from '@components/Banner';
19
+ import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue';
19
20
 
20
21
  import { SUBTYPE_MAPPING, VERBS } from '@shell/models/management.cattle.io.roletemplate';
21
22
  import Loading from '@shell/components/Loading';
@@ -63,7 +64,8 @@ export default {
63
64
  SortableTable,
64
65
  Loading,
65
66
  Error,
66
- Banner
67
+ Banner,
68
+ LabeledInput
67
69
  },
68
70
 
69
71
  mixins: [CreateEditView, FormValidation],
@@ -706,6 +708,7 @@ export default {
706
708
  :options="verbOptions"
707
709
  :multiple="true"
708
710
  :mode="mode"
711
+ :compact="true"
709
712
  :data-testid="`grant-resources-verbs${props.i}`"
710
713
  @update:value="updateSelectValue(props.row.value, 'verbs', $event)"
711
714
  />
@@ -719,31 +722,32 @@ export default {
719
722
  :searchable="true"
720
723
  :taggable="true"
721
724
  :mode="mode"
725
+ :compact="true"
722
726
  :data-testid="`grant-resources-resources${props.i}`"
723
727
  @update:value="setRule('resources', props.row.value, $event)"
724
728
  @createdListItem="setRule('resources', props.row.value, $event)"
725
729
  />
726
730
  </div>
727
731
  <div :class="ruleClass">
728
- <input
732
+ <LabeledInput
729
733
  :value="getRule('apiGroups', props.row.value)"
730
734
  :disabled="isBuiltin"
731
735
  :mode="mode"
732
736
  :data-testid="`grant-resources-api-groups${props.i}`"
733
737
  @input="setRule('apiGroups', props.row.value, $event.target.value)"
734
- >
738
+ />
735
739
  </div>
736
740
  <div
737
741
  v-if="!isNamespaced"
738
742
  :class="ruleClass"
739
743
  >
740
- <input
744
+ <LabeledInput
741
745
  :value="getRule('nonResourceURLs', props.row.value)"
742
746
  :disabled="isBuiltin"
743
747
  :mode="mode"
744
748
  :data-testid="`grant-resources-non-resource-urls${props.i}`"
745
749
  @input="setRule('nonResourceURLs', props.row.value, $event.target.value)"
746
- >
750
+ />
747
751
  </div>
748
752
  </div>
749
753
  </template>
@@ -777,6 +781,7 @@ export default {
777
781
  option-key="value"
778
782
  option-label="label"
779
783
  :mode="mode"
784
+ :compact="true"
780
785
  @on-focus="selectFocused = props.i"
781
786
  @on-blur="selectFocused = null"
782
787
  />
@@ -813,18 +818,9 @@ export default {
813
818
  }
814
819
 
815
820
  .columns {
816
- & > .col {
817
- &:not(:first-of-type) {
818
- height: $input-height;
819
- }
820
-
821
- &:first-of-type {
822
- min-height: $input-height;
823
- }
824
-
825
- & > * {
826
- height: 100%;
827
- }
821
+ .col > .unlabeled-select:not(.taggable) {
822
+ // override the odd padding-top from shell/assets/styles/global/_select.scss
823
+ padding: $unlabaled-select-padding
828
824
  }
829
825
  }
830
826
  }
@@ -188,7 +188,7 @@ export default {
188
188
  :filterable="false"
189
189
  class="select-principal"
190
190
  :class="{'retain-selection': retainSelection}"
191
- @input="add"
191
+ @update:value="add"
192
192
  @search="onSearch"
193
193
  @on-open="resetTooltipContent()"
194
194
  @on-close="setTooltipContent()"
@@ -168,21 +168,20 @@ function toPercent(value, min, max) {
168
168
  <div class="meta-title">
169
169
  {{ meta.readyCount }} / {{ meta.total }} {{ title }} ready <i class="icon toggle icon-chevron-down" />
170
170
  </div>
171
- <template
172
- #popover
173
- class="resources-status-list"
174
- >
175
- <ul
176
- class="list-unstyled dropdown"
177
- @click.stop="showMenu(false)"
178
- >
179
- <li
180
- v-for="(val, idx) in values"
181
- :key="idx"
171
+ <template #popper>
172
+ <div class="resources-status-list">
173
+ <ul
174
+ class="list-unstyled dropdown"
175
+ @click.stop="showMenu(false)"
182
176
  >
183
- <span>{{ val.label }}</span><span class="list-count">{{ val.count }}</span>
184
- </li>
185
- </ul>
177
+ <li
178
+ v-for="(val, idx) in values"
179
+ :key="idx"
180
+ >
181
+ <span>{{ val.label }}</span><span class="list-count">{{ val.count }}</span>
182
+ </li>
183
+ </ul>
184
+ </div>
186
185
  </template>
187
186
  </v-dropdown>
188
187
  </div>
@@ -86,7 +86,7 @@ export default {
86
86
  }
87
87
  },
88
88
  data() {
89
- const input = (this.value || []).slice();
89
+ const input = (Array.isArray(this.value) ? this.value : []).slice();
90
90
  const rows = [];
91
91
 
92
92
  for ( const value of input ) {
@@ -37,8 +37,17 @@ export default {
37
37
  type: String,
38
38
  default: _EDIT,
39
39
  },
40
+
41
+ value: {
42
+ type: Object,
43
+ default: () => {
44
+ return {};
45
+ },
46
+ },
40
47
  },
41
48
 
49
+ emits: ['update:value', 'add', 'remove'],
50
+
42
51
  computed: {
43
52
  isView() {
44
53
  return this.mode === _VIEW;
@@ -67,6 +76,7 @@ export default {
67
76
  <template>
68
77
  <ArrayList
69
78
  class="array-list-grouped"
79
+ :value="value"
70
80
  v-bind="$attrs"
71
81
  :add-allowed="canAdd && !isView"
72
82
  :mode="mode"
@@ -95,12 +105,15 @@ export default {
95
105
  <!-- Pass down templates provided by the caller -->
96
106
  <template
97
107
  v-for="(_, slot) of $slots"
98
- v-slot:[slot]="scope"
108
+ #[slot]="scope"
109
+ :key="slot"
99
110
  >
100
- <slot
101
- :name="slot"
102
- v-bind="scope"
103
- />
111
+ <template v-if="typeof $slots[slot] === 'function'">
112
+ <slot
113
+ :name="slot"
114
+ v-bind="scope"
115
+ />
116
+ </template>
104
117
  </template>
105
118
  </ArrayList>
106
119
  </template>
@@ -13,6 +13,8 @@ import { LABEL_SELECT_NOT_OPTION_KINDS } from '@shell/types/components/labeledSe
13
13
  export default {
14
14
  name: 'LabeledSelect',
15
15
 
16
+ inheritAttrs: false,
17
+
16
18
  components: { LabeledTooltip },
17
19
  mixins: [
18
20
  CompactInput,
@@ -247,17 +249,20 @@ export default {
247
249
  <div
248
250
  ref="select"
249
251
  class="labeled-select"
250
- :class="{
251
- disabled: isView || disabled,
252
- focused,
253
- [mode]: true,
254
- [status]: status,
255
- taggable: $attrs.taggable,
256
- taggable: $attrs.multiple,
257
- hoverable: hoverTooltip,
258
- 'compact-input': isCompact,
259
- 'no-label': !hasLabel,
260
- }"
252
+ :class="[
253
+ $attrs.class,
254
+ {
255
+ disabled: isView || disabled,
256
+ focused,
257
+ [mode]: true,
258
+ [status]: status,
259
+ taggable: $attrs.taggable,
260
+ taggable: $attrs.multiple,
261
+ hoverable: hoverTooltip,
262
+ 'compact-input': isCompact,
263
+ 'no-label': !hasLabel
264
+ }
265
+ ]"
261
266
  @click="focusSearch"
262
267
  @focus="focusSearch"
263
268
  >
@@ -81,6 +81,11 @@ export default {
81
81
  type: Boolean,
82
82
  default: true
83
83
  },
84
+
85
+ compact: {
86
+ type: Boolean,
87
+ default: null
88
+ },
84
89
  },
85
90
 
86
91
  methods: {
@@ -206,6 +211,11 @@ export default {
206
211
  },
207
212
  canPaginate() {
208
213
  return false;
214
+ },
215
+ deClassedAttrs() {
216
+ const { class: _, ...rest } = this.$attrs;
217
+
218
+ return rest;
209
219
  }
210
220
  }
211
221
  };
@@ -222,13 +232,14 @@ export default {
222
232
  [status]: status,
223
233
  taggable: $attrs.taggable,
224
234
  taggable: $attrs.multiple,
235
+ 'compact-input': compact,
225
236
  [$attrs.class]: $attrs.class
226
237
  }"
227
238
  @focus="focusSearch"
228
239
  >
229
240
  <v-select
230
241
  ref="select-input"
231
- v-bind="$attrs"
242
+ v-bind="deClassedAttrs"
232
243
  class="inline"
233
244
  :class="{'select-input-view': mode === 'view'}"
234
245
  :autoscroll="true"
@@ -325,5 +336,10 @@ export default {
325
336
  }
326
337
 
327
338
  @include input-status-color;
339
+
340
+ &.compact-input {
341
+ min-height: $unlabeled-input-height;
342
+ line-height: $input-line-height;
343
+ }
328
344
  }
329
345
  </style>
@@ -14,16 +14,17 @@ describe('component: Command', () => {
14
14
  expect(inputWraps).toHaveLength(5);
15
15
  });
16
16
 
17
- it.skip.each([
17
+ it.each([
18
18
  'command',
19
19
  'args',
20
20
  'workingDir',
21
- ])('(Vue3 Skip) should emit an update on %p input', (field) => {
21
+ ])('should emit an update on %p input', (field) => {
22
22
  const wrapper = mount(Command, { props: { mode: _EDIT } });
23
- const input = wrapper.find(`[data-testid="input-command-${ field }"]`).find('input');
24
- const newValue = 123;
23
+ const inputComponent = wrapper.getComponent(`[data-testid="input-command-${ field }"]>*`);
24
+
25
+ const newValue = ['123'];
25
26
 
26
- input.setValue(newValue);
27
+ inputComponent.vm.$emit('update:value', newValue);
27
28
 
28
29
  expect(wrapper.emitted('update:value')).toHaveLength(1);
29
30
  });