@rancher/shell 0.3.8 → 0.3.9

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 (36) hide show
  1. package/assets/translations/en-us.yaml +28 -2
  2. package/babel.config.js +17 -4
  3. package/components/CodeMirror.vue +146 -14
  4. package/components/ContainerResourceLimit.vue +14 -1
  5. package/components/CruResource.vue +21 -5
  6. package/components/ExplorerProjectsNamespaces.vue +5 -1
  7. package/components/GroupPanel.vue +57 -0
  8. package/components/YamlEditor.vue +2 -2
  9. package/components/form/ArrayList.vue +1 -1
  10. package/components/form/KeyValue.vue +34 -1
  11. package/components/form/MatchExpressions.vue +120 -21
  12. package/components/form/NodeAffinity.vue +54 -4
  13. package/components/form/PodAffinity.vue +160 -47
  14. package/components/form/Tolerations.vue +40 -4
  15. package/components/form/__tests__/ArrayList.test.ts +3 -3
  16. package/components/form/__tests__/MatchExpressions.test.ts +1 -1
  17. package/components/nav/Header.vue +2 -0
  18. package/config/settings.ts +6 -1
  19. package/core/plugins-loader.js +0 -2
  20. package/edit/configmap.vue +33 -6
  21. package/edit/provisioning.cattle.io.cluster/AgentConfiguration.vue +326 -0
  22. package/edit/provisioning.cattle.io.cluster/index.vue +1 -0
  23. package/edit/provisioning.cattle.io.cluster/rke2.vue +60 -0
  24. package/mixins/chart.js +1 -1
  25. package/models/batch.cronjob.js +18 -3
  26. package/models/workload.js +1 -1
  27. package/package.json +2 -3
  28. package/pages/auth/login.vue +1 -0
  29. package/pages/prefs.vue +18 -2
  30. package/pkg/vue.config.js +0 -1
  31. package/plugins/codemirror.js +158 -0
  32. package/public/index.html +1 -1
  33. package/types/shell/index.d.ts +20 -1
  34. package/utils/create-yaml.js +105 -8
  35. package/utils/settings.ts +12 -0
  36. package/vue.config.js +2 -2
@@ -0,0 +1,326 @@
1
+ <script>
2
+ import { Banner } from '@components/Banner';
3
+ import GroupPanel from '@shell/components/GroupPanel';
4
+ import PodAffinity from '@shell/components/form/PodAffinity';
5
+ import NodeAffinity from '@shell/components/form/NodeAffinity';
6
+ import ContainerResourceLimit from '@shell/components/ContainerResourceLimit';
7
+ import Tolerations from '@shell/components/form/Tolerations';
8
+ import { cleanUp } from '@shell/utils/object';
9
+ import { fetchSetting } from '@shell/utils/settings';
10
+ import { RadioGroup } from '@components/Form/Radio';
11
+
12
+ export function cleanAgentConfiguration(model, key) {
13
+ if (!model || !model[key]) {
14
+ return;
15
+ }
16
+
17
+ const v = model[key];
18
+
19
+ if (Array.isArray(v) && v.length === 0) {
20
+ delete model[key];
21
+ } else if (v && typeof v === 'object') {
22
+ Object.keys(v).forEach((k) => {
23
+ // delete these auxiliary props used in podAffinity and nodeAffinity that shouldn't be sent to the server
24
+ if (k === '_namespaceOption' || k === '_namespaces' || k === '_anti' || k === '_id') {
25
+ delete v[k];
26
+ }
27
+
28
+ // prevent cleanup of namespaceSelector when an empty object because it represents all namespaces in pod/node affinity
29
+ // https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#podaffinityterm-v1-core
30
+ if (k !== 'namespaceSelector') {
31
+ cleanAgentConfiguration(v, k);
32
+ }
33
+ });
34
+
35
+ if (Object.keys(v).length === 0) {
36
+ delete model[key];
37
+ }
38
+ }
39
+ }
40
+
41
+ // Affinity radio button choices
42
+ const DEFAULT = 'default';
43
+ const CUSTOM = 'custom';
44
+
45
+ // This is the form for Agent Configuration
46
+ // Used for both Cluster Agent and Fleet Agent configuration
47
+ export default {
48
+ components: {
49
+ Banner,
50
+ ContainerResourceLimit,
51
+ GroupPanel,
52
+ PodAffinity,
53
+ NodeAffinity,
54
+ RadioGroup,
55
+ Tolerations,
56
+ },
57
+ props: {
58
+ value: {
59
+ type: Object,
60
+ default: () => {},
61
+ },
62
+
63
+ mode: {
64
+ type: String,
65
+ required: true,
66
+ },
67
+
68
+ type: {
69
+ type: String,
70
+ required: true,
71
+ }
72
+ },
73
+
74
+ async fetch() {
75
+ // Default affinity
76
+ const settingId = `${ this.type }-agent-default-affinity`;
77
+ const setting = await fetchSetting(this.$store, settingId);
78
+
79
+ if (setting) {
80
+ try {
81
+ const parsed = JSON.parse(setting.value || setting.default);
82
+
83
+ this.defaultAffinity = parsed || {};
84
+ } catch (e) {
85
+ console.error('Could not parse agent default setting', e); // eslint-disable-line no-console
86
+ this.defaultAffinity = {};
87
+ }
88
+ }
89
+ },
90
+
91
+ data() {
92
+ const nodeAffinity = this.value?.overrideAffinity?.nodeAffinity;
93
+ const podAffinity = this.value?.overrideAffinity?.podAffinity;
94
+ const podAntiAffinity = this.value?.overrideAffinity?.podAntiAffinity;
95
+
96
+ let hasAffinityPopulated = false;
97
+
98
+ if ((nodeAffinity && Object.keys(nodeAffinity).length) ||
99
+ (podAffinity && Object.keys(podAffinity).length) ||
100
+ (podAntiAffinity && Object.keys(podAntiAffinity).length)) {
101
+ hasAffinityPopulated = true;
102
+ }
103
+
104
+ return {
105
+ defaultAffinity: {},
106
+ affinitySetting: hasAffinityPopulated ? CUSTOM : DEFAULT,
107
+ nodeAffinity: {}
108
+ };
109
+ },
110
+
111
+ created() {
112
+ this.ensureValue();
113
+ },
114
+
115
+ computed: {
116
+ flatResources: {
117
+ get() {
118
+ const { limits = {}, requests = {} } = this.value.overrideResourceRequirements || {};
119
+ const {
120
+ cpu: limitsCpu,
121
+ memory: limitsMemory,
122
+ } = limits;
123
+ const { cpu: requestsCpu, memory: requestsMemory } = requests;
124
+
125
+ return {
126
+ limitsCpu,
127
+ limitsMemory,
128
+ requestsCpu,
129
+ requestsMemory,
130
+ };
131
+ },
132
+ set(neu) {
133
+ const {
134
+ limitsCpu,
135
+ limitsMemory,
136
+ requestsCpu,
137
+ requestsMemory,
138
+ } = neu;
139
+
140
+ const existing = this.value?.overrideResourceRequirements || {};
141
+
142
+ delete existing.requests;
143
+ delete existing.limits;
144
+
145
+ const out = {
146
+ ...existing,
147
+ requests: {
148
+ cpu: requestsCpu,
149
+ memory: requestsMemory,
150
+ },
151
+ limits: {
152
+ cpu: limitsCpu,
153
+ memory: limitsMemory,
154
+ },
155
+ };
156
+
157
+ this.$set(this.value, 'overrideResourceRequirements', cleanUp(out));
158
+ },
159
+ },
160
+
161
+ affinityOptions() {
162
+ return [{
163
+ label: this.t('cluster.agentConfig.affinity.default'),
164
+ value: DEFAULT,
165
+ }, {
166
+ label: this.t('cluster.agentConfig.affinity.custom'),
167
+ value: CUSTOM,
168
+ }];
169
+ },
170
+
171
+ canEditAffinity() {
172
+ return this.affinitySetting === CUSTOM;
173
+ }
174
+ },
175
+
176
+ watch: {
177
+ value() {
178
+ this.ensureValue();
179
+ }
180
+ },
181
+
182
+ methods: {
183
+ ensureValue() {
184
+ // Ensure we have the model structure needed for the form controls
185
+ if (this.value) {
186
+ this.value.overrideAffinity = this.value.overrideAffinity || {};
187
+ this.value.appendTolerations = this.value.appendTolerations || [];
188
+ this.value.overrideResourceRequirements = this.value.overrideResourceRequirements || {};
189
+
190
+ this.nodeAffinity = this.value?.overrideAffinity?.nodeAffinity || {};
191
+ }
192
+ },
193
+
194
+ affinitySettingChange() {
195
+ if (this.affinitySetting === CUSTOM) {
196
+ const parsedDefaultAffinites = JSON.parse(JSON.stringify(this.defaultAffinity));
197
+
198
+ // Copy the default so that the user can edit it
199
+ // this will cover the pod affinities
200
+ this.$set(this.value, 'overrideAffinity', parsedDefaultAffinites);
201
+
202
+ // in order not to break the node affinity component, let's go for a slightly different way of handling the logic here
203
+ if (parsedDefaultAffinites.nodeAffinity) {
204
+ this.nodeAffinity = parsedDefaultAffinites.nodeAffinity;
205
+ }
206
+ } else {
207
+ this.$set(this.value, 'overrideAffinity', {});
208
+ }
209
+ },
210
+ updateNodeAffinity(val) {
211
+ this.$set(this.value.overrideAffinity, 'nodeAffinity', val);
212
+ }
213
+ }
214
+ };
215
+ </script>
216
+
217
+ <template>
218
+ <div v-if="value && Object.keys(value).length">
219
+ <Banner
220
+ :closable="false"
221
+ color="info"
222
+ label-key="cluster.agentConfig.banners.advanced"
223
+ />
224
+
225
+ <GroupPanel
226
+ label-key="cluster.agentConfig.groups.podRequestsAndLimits"
227
+ class="mt-20"
228
+ >
229
+ <Banner
230
+ :closable="false"
231
+ color="info"
232
+ label-key="cluster.agentConfig.banners.limits"
233
+ />
234
+ <ContainerResourceLimit
235
+ v-model="flatResources"
236
+ :mode="mode"
237
+ :show-tip="false"
238
+ :handle-gpu-limit="false"
239
+ class="mt-10"
240
+ />
241
+ </GroupPanel>
242
+
243
+ <GroupPanel
244
+ label-key="cluster.agentConfig.groups.podTolerations"
245
+ class="mt-20"
246
+ >
247
+ <Banner
248
+ :closable="false"
249
+ color="info"
250
+ label-key="cluster.agentConfig.banners.tolerations"
251
+ />
252
+ <Tolerations
253
+ v-model="value.appendTolerations"
254
+ :mode="mode"
255
+ class="mt-10"
256
+ />
257
+ </GroupPanel>
258
+
259
+ <GroupPanel
260
+ label-key="cluster.agentConfig.groups.podAffinity"
261
+ class="mt-20"
262
+ >
263
+ <RadioGroup
264
+ v-model="affinitySetting"
265
+ name="affinity-override"
266
+ :mode="mode"
267
+ :options="affinityOptions"
268
+ class="mt-10"
269
+ data-testid="affinity-options"
270
+ @input="affinitySettingChange"
271
+ />
272
+
273
+ <Banner
274
+ v-if="canEditAffinity"
275
+ :closable="false"
276
+ color="warning"
277
+ >
278
+ <p v-clean-html="t('cluster.agentConfig.banners.windowsCompatibility', {}, true)" />
279
+ </Banner>
280
+
281
+ <h4 v-if="canEditAffinity">
282
+ {{ t('cluster.agentConfig.subGroups.podAffinityAnti') }}
283
+ </h4>
284
+
285
+ <PodAffinity
286
+ v-if="canEditAffinity"
287
+ v-model="value"
288
+ field="overrideAffinity"
289
+ :mode="mode"
290
+ class="mt-0 mb-20"
291
+ :all-namespaces-option-available="true"
292
+ :force-input-namespace-selection="true"
293
+ :remove-labeled-input-namespace-label="true"
294
+ data-testid="pod-affinity"
295
+ />
296
+
297
+ <div
298
+ v-if="canEditAffinity"
299
+ class="separator"
300
+ />
301
+ <h4
302
+ v-if="canEditAffinity"
303
+ class="mt-20"
304
+ >
305
+ {{ t('cluster.agentConfig.subGroups.nodeAffinity') }}
306
+ </h4>
307
+
308
+ <NodeAffinity
309
+ v-if="canEditAffinity"
310
+ v-model="nodeAffinity"
311
+ :matching-selector-display="true"
312
+ :mode="mode"
313
+ class="mt-0"
314
+ data-testid="node-affinity"
315
+ @input="updateNodeAffinity"
316
+ />
317
+ </GroupPanel>
318
+ </div>
319
+ </template>
320
+
321
+ <style lang="scss" scoped>
322
+ .separator {
323
+ width: 100%;
324
+ border-top: 1px solid var(--border);
325
+ }
326
+ </style>
@@ -477,6 +477,7 @@ export default {
477
477
  :errors="errors"
478
478
  :subtypes="subTypes"
479
479
  :cancel-event="true"
480
+ :prevent-enter-submit="true"
480
481
  class="create-cluster"
481
482
  @finish="save"
482
483
  @cancel="cancel"
@@ -69,6 +69,7 @@ import S3Config from './S3Config';
69
69
  import SelectCredential from './SelectCredential';
70
70
  import AdvancedSection from '@shell/components/AdvancedSection.vue';
71
71
  import { ELEMENTAL_SCHEMA_IDS, KIND, ELEMENTAL_CLUSTER_PROVIDER } from '../../config/elemental-types';
72
+ import AgentConfiguration, { cleanAgentConfiguration } from './AgentConfiguration';
72
73
 
73
74
  const PUBLIC = 'public';
74
75
  const PRIVATE = 'private';
@@ -96,6 +97,8 @@ const NODE_TOTAL = {
96
97
  icon: 'icon-checkmark'
97
98
  }
98
99
  };
100
+ const CLUSTER_AGENT_CUSTOMIZATION = 'clusterAgentDeploymentCustomization';
101
+ const FLEET_AGENT_CUSTOMIZATION = 'fleetAgentDeploymentCustomization';
99
102
 
100
103
  export default {
101
104
  components: {
@@ -107,6 +110,7 @@ export default {
107
110
  BadgeState,
108
111
  Banner,
109
112
  Checkbox,
113
+ AgentConfiguration,
110
114
  ClusterMembershipEditor,
111
115
  CruResource,
112
116
  DrainOptions,
@@ -274,6 +278,18 @@ export default {
274
278
 
275
279
  this.userChartValues[key] = value;
276
280
  });
281
+
282
+ // Ensure we have empty models for the two agent configurations
283
+
284
+ // Cluster Agent Configuration
285
+ if ( !this.value.spec[CLUSTER_AGENT_CUSTOMIZATION]) {
286
+ set(this.value.spec, CLUSTER_AGENT_CUSTOMIZATION, {});
287
+ }
288
+
289
+ // Fleet Agent Configuration
290
+ if ( !this.value.spec[FLEET_AGENT_CUSTOMIZATION] ) {
291
+ set(this.value.spec, FLEET_AGENT_CUSTOMIZATION, {});
292
+ }
277
293
  },
278
294
 
279
295
  data() {
@@ -1081,6 +1097,7 @@ export default {
1081
1097
  created() {
1082
1098
  this.registerBeforeHook(this.saveMachinePools, 'save-machine-pools');
1083
1099
  this.registerBeforeHook(this.setRegistryConfig, 'set-registry-config');
1100
+ this.registerBeforeHook(this.agentConfigurationCleanup, 'cleanup-agent-config');
1084
1101
  this.registerAfterHook(this.cleanupMachinePools, 'cleanup-machine-pools');
1085
1102
  this.registerAfterHook(this.saveRoleBindings, 'save-role-bindings');
1086
1103
  },
@@ -1089,6 +1106,12 @@ export default {
1089
1106
  nlToBr,
1090
1107
  set,
1091
1108
 
1109
+ agentConfigurationCleanup() {
1110
+ // Clean agent configuration objects, so we only send values when the user has configured something
1111
+ cleanAgentConfiguration(this.value.spec, CLUSTER_AGENT_CUSTOMIZATION);
1112
+ cleanAgentConfiguration(this.value.spec, FLEET_AGENT_CUSTOMIZATION);
1113
+ },
1114
+
1092
1115
  /**
1093
1116
  * set instanceNameLimit to 15 to all pool machine if truncateHostnames checkbox is clicked
1094
1117
  */
@@ -1467,7 +1490,20 @@ export default {
1467
1490
  delete this.value.spec.rkeConfig.machineGlobalConfig.profile;
1468
1491
  }
1469
1492
 
1493
+ // store the current data for fleet and cluster agent so that we can re-apply it later if the save fails
1494
+ // we also have a before hook (check created() hooks) where the cleanup of the data occurs
1495
+ const clusterAgentDeploymentCustomization = JSON.parse(JSON.stringify(this.value.spec[CLUSTER_AGENT_CUSTOMIZATION]));
1496
+ const fleetAgentDeploymentCustomization = JSON.parse(JSON.stringify(this.value.spec[FLEET_AGENT_CUSTOMIZATION]));
1497
+
1470
1498
  await this.save(btnCb);
1499
+
1500
+ // comes from createEditView mixin
1501
+ // if there are any errors saving, restore the agent config data
1502
+ if (this.errors?.length) {
1503
+ // Ensure the agent configuration is set back to the values before we changed (cleaned) it
1504
+ set(this.value.spec, CLUSTER_AGENT_CUSTOMIZATION, clusterAgentDeploymentCustomization);
1505
+ set(this.value.spec, FLEET_AGENT_CUSTOMIZATION, fleetAgentDeploymentCustomization);
1506
+ }
1471
1507
  },
1472
1508
  // create a secret to reference the harvester cluster kubeconfig in rkeConfig
1473
1509
  async createKubeconfigSecret(kubeconfig = '') {
@@ -2821,6 +2857,30 @@ export default {
2821
2857
  </div>
2822
2858
  </Tab>
2823
2859
 
2860
+ <!-- Cluster Agent Configuration -->
2861
+ <Tab
2862
+ name="clusteragentconfig"
2863
+ label-key="cluster.agentConfig.tabs.cluster"
2864
+ >
2865
+ <AgentConfiguration
2866
+ v-model="value.spec.clusterAgentDeploymentCustomization"
2867
+ type="cluster"
2868
+ :mode="mode"
2869
+ />
2870
+ </Tab>
2871
+
2872
+ <!-- Fleet Agent Configuration -->
2873
+ <Tab
2874
+ name="fleetagentconfig"
2875
+ label-key="cluster.agentConfig.tabs.fleet"
2876
+ >
2877
+ <AgentConfiguration
2878
+ v-model="value.spec.fleetAgentDeploymentCustomization"
2879
+ type="fleet"
2880
+ :mode="mode"
2881
+ />
2882
+ </Tab>
2883
+
2824
2884
  <!-- Advanced -->
2825
2885
  <Tab
2826
2886
  v-if="haveArgInfo || agentArgs['protect-kernel-defaults']"
package/mixins/chart.js CHANGED
@@ -14,7 +14,7 @@ import { CAPI, CATALOG } from '@shell/config/types';
14
14
  import { isPrerelease } from '@shell/utils/version';
15
15
  import difference from 'lodash/difference';
16
16
  import { LINUX } from '@shell/store/catalog';
17
- import { clone } from 'utils/object';
17
+ import { clone } from '@shell/utils/object';
18
18
  import { merge } from 'lodash';
19
19
 
20
20
  export default {
@@ -2,6 +2,7 @@ import { insertAt } from '@shell/utils/array';
2
2
  import { clone } from '@shell/utils/object';
3
3
  import { WORKLOAD_TYPES } from '@shell/config/types';
4
4
  import Workload from './workload';
5
+ import { WORKLOAD_TYPE_TO_KIND_MAPPING } from '@shell/detail/workload/index';
5
6
 
6
7
  export default class CronJob extends Workload {
7
8
  get state() {
@@ -47,12 +48,26 @@ export default class CronJob extends Workload {
47
48
  }
48
49
 
49
50
  async runNow() {
50
- const job = await this.$dispatch('create', clone(this.spec.jobTemplate));
51
+ const ownerRef = {
52
+ apiVersion: this.apiVersion,
53
+ controller: true,
54
+ kind: this.kind,
55
+ name: this.metadata.name,
56
+ uid: this.metadata.uid
57
+ };
58
+
59
+ // Set type and kind to ensure the correct model is returned (via classify). This object will be persisted to the store
60
+ const job = await this.$dispatch('create', {
61
+ type: WORKLOAD_TYPES.JOB,
62
+ kind: WORKLOAD_TYPE_TO_KIND_MAPPING[WORKLOAD_TYPES.JOB],
63
+ ...clone(this.spec.jobTemplate)
64
+ });
51
65
 
52
- job.type = WORKLOAD_TYPES.JOB;
53
66
  job.metadata = job.metadata || {};
54
67
  job.metadata.namespace = this.metadata.namespace;
55
- job.metadata.generateName = `${ this.metadata.name }-`;
68
+ // Can't use `generatedName` and no `name`... as this fails schema validation
69
+ job.metadata.name = `${ this.metadata.name }-${ Date.now() }`;
70
+ job.metadata.ownerReferences = [ownerRef];
56
71
 
57
72
  await job.save();
58
73
 
@@ -296,7 +296,7 @@ export default class Workload extends WorkloadService {
296
296
  }
297
297
 
298
298
  get endpoint() {
299
- return this?.metadata?.annotations[CATTLE_PUBLIC_ENDPOINTS];
299
+ return this?.metadata?.annotations?.[CATTLE_PUBLIC_ENDPOINTS];
300
300
  }
301
301
 
302
302
  get desired() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -69,7 +69,7 @@
69
69
  "dagre-d3": "0.6.4",
70
70
  "dayjs": "1.8.29",
71
71
  "diff2html": "2.11.2",
72
- "dompurify": "2.0.12",
72
+ "dompurify": "2.4.5",
73
73
  "eslint": "7.32.0",
74
74
  "eslint-config-standard": "16.0.3",
75
75
  "eslint-import-resolver-node": "0.3.4",
@@ -89,7 +89,6 @@
89
89
  "jest": "27.5.1",
90
90
  "jest-serializer-vue": "2.0.2",
91
91
  "jexl": "2.2.2",
92
- "jquery": "3.5.1",
93
92
  "js-cookie": "2.2.1",
94
93
  "js-yaml": "4.1.0",
95
94
  "js-yaml-loader": "1.2.2",
@@ -303,6 +303,7 @@ export default {
303
303
  </h1>
304
304
  <div
305
305
  class="login-messages"
306
+ data-testid="login__messages"
306
307
  :class="{'login-messages--hasContent': hasLoginMessage}"
307
308
  >
308
309
  <Banner
package/pages/prefs.vue CHANGED
@@ -163,7 +163,9 @@ export default {
163
163
  <h4 v-t="'prefs.language'" />
164
164
  <div class="row">
165
165
  <div class="col span-4">
166
- <LocaleSelector />
166
+ <LocaleSelector
167
+ data-testid="prefs__languageSelector"
168
+ />
167
169
  </div>
168
170
  </div>
169
171
  </div>
@@ -173,6 +175,7 @@ export default {
173
175
  <h4 v-t="'prefs.theme.label'" />
174
176
  <ButtonGroup
175
177
  v-model="theme"
178
+ data-testid="prefs__themeOptions"
176
179
  :options="themeOptions"
177
180
  />
178
181
  <div class="mt-10">
@@ -190,7 +193,9 @@ export default {
190
193
  >
191
194
  <hr>
192
195
  <h4 v-t="'prefs.landing.label'" />
193
- <LandingPagePreference />
196
+ <LandingPagePreference
197
+ data-testid="prefs__landingPagePreference"
198
+ />
194
199
  </div>
195
200
  <!-- Display Settings -->
196
201
  <div class="mt-10 mb-10">
@@ -203,6 +208,7 @@ export default {
203
208
  <div class="col span-4">
204
209
  <LabeledSelect
205
210
  v-model="dateFormat"
211
+ data-testid="prefs__displaySetting__dateFormat"
206
212
  :label="t('prefs.dateFormat.label')"
207
213
  :options="dateOptions"
208
214
  />
@@ -210,6 +216,7 @@ export default {
210
216
  <div class="col span-4">
211
217
  <LabeledSelect
212
218
  v-model="timeFormat"
219
+ data-testid="prefs__displaySetting__timeFormat"
213
220
  :label="t('prefs.timeFormat.label')"
214
221
  :options="timeOptions"
215
222
  />
@@ -220,6 +227,7 @@ export default {
220
227
  <div class="col span-4">
221
228
  <LabeledSelect
222
229
  v-model.number="perPage"
230
+ data-testid="prefs__displaySetting__perPage"
223
231
  :label="t('prefs.perPage.label')"
224
232
  :options="perPageOptions"
225
233
  option-key="value"
@@ -230,6 +238,7 @@ export default {
230
238
  <div class="col span-4">
231
239
  <LabeledSelect
232
240
  v-model.number="menuMaxClusters"
241
+ data-testid="prefs__displaySetting__menuMaxClusters"
233
242
  :label="t('prefs.clusterToShow.label')"
234
243
  :options="menuClusterOptions"
235
244
  option-key="value"
@@ -245,6 +254,7 @@ export default {
245
254
  <h4 v-t="'prefs.confirmationSetting.title'" />
246
255
  <Checkbox
247
256
  v-model="scalingDownPrompt"
257
+ data-testid="prefs__scalingDownPrompt"
248
258
  :label="t('prefs.confirmationSetting.scalingDownPrompt')"
249
259
  class="mt-10"
250
260
  />
@@ -255,18 +265,21 @@ export default {
255
265
  <h4 v-t="'prefs.advFeatures.title'" />
256
266
  <Checkbox
257
267
  v-model="viewInApi"
268
+ data-testid="prefs__viewInApi"
258
269
  :label="t('prefs.advFeatures.viewInApi', {}, true)"
259
270
  class="mt-10"
260
271
  />
261
272
  <br>
262
273
  <Checkbox
263
274
  v-model="allNamespaces"
275
+ data-testid="prefs__allNamespaces"
264
276
  :label="t('prefs.advFeatures.allNamespaces', {}, true)"
265
277
  class="mt-20"
266
278
  />
267
279
  <br>
268
280
  <Checkbox
269
281
  v-model="themeShortcut"
282
+ data-testid="prefs__themeShortcut"
270
283
  :label="t('prefs.advFeatures.themeShortcut', {}, true)"
271
284
  class="mt-20"
272
285
  />
@@ -274,6 +287,7 @@ export default {
274
287
  <Checkbox
275
288
  v-if="!isSingleProduct"
276
289
  v-model="hideDescriptions"
290
+ data-testid="prefs__hideDescriptions"
277
291
  :label="t('prefs.hideDesc.label')"
278
292
  class="mt-20"
279
293
  />
@@ -292,6 +306,7 @@ export default {
292
306
  <h4 v-t="'prefs.keymap.label'" />
293
307
  <ButtonGroup
294
308
  v-model="keymap"
309
+ data-testid="prefs__keymapOptions"
295
310
  :options="keymapOptions"
296
311
  />
297
312
  </div>
@@ -304,6 +319,7 @@ export default {
304
319
  <h4 v-t="'prefs.helm.label'" />
305
320
  <ButtonGroup
306
321
  v-model="showPreRelease"
322
+ data-testid="prefs__helmOptions"
307
323
  :options="helmOptions"
308
324
  />
309
325
  </div>
package/pkg/vue.config.js CHANGED
@@ -82,7 +82,6 @@ module.exports = function(dir) {
82
82
  // These modules will be externalised and not included with the build of a package library
83
83
  // This helps reduce the package size, but these dependencies must be provided by the hosting application
84
84
  config.externals = {
85
- jquery: '$',
86
85
  jszip: '__jszip',
87
86
  'js-yaml': '__jsyaml'
88
87
  };