@rancher/shell 0.3.9 → 0.3.10

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 (127) hide show
  1. package/assets/translations/en-us.yaml +19 -24
  2. package/assets/translations/zh-hans.yaml +82 -16
  3. package/chart/istio.vue +11 -11
  4. package/chart/rancher-backup/S3.vue +1 -1
  5. package/components/AsyncButton.vue +2 -2
  6. package/components/ButtonGroup.vue +1 -1
  7. package/components/CompoundStatusBadge.vue +1 -1
  8. package/components/CopyCode.vue +1 -1
  9. package/components/DetailTop.vue +1 -1
  10. package/components/ExplorerProjectsNamespaces.vue +3 -3
  11. package/components/GlobalRoleBindings.vue +1 -1
  12. package/components/HarvesterServiceAddOnConfig.vue +2 -117
  13. package/components/ResourceDetail/Masthead.vue +1 -1
  14. package/components/ResourceList/Masthead.vue +0 -6
  15. package/components/ResourceList/ResourceLoadingIndicator.vue +1 -9
  16. package/components/ResourceList/index.vue +7 -6
  17. package/components/ResourceTable.vue +13 -3
  18. package/components/SortableTable/THead.vue +3 -3
  19. package/components/SortableTable/index.vue +3 -3
  20. package/components/Tabbed/Tab.vue +1 -1
  21. package/components/Tabbed/index.vue +1 -1
  22. package/components/Wizard.vue +9 -6
  23. package/components/__tests__/NamespaceFilter.test.ts +26 -7
  24. package/components/auth/RoleDetailEdit.vue +1 -1
  25. package/components/auth/SelectPrincipal.vue +1 -1
  26. package/components/fleet/FleetRepos.vue +1 -1
  27. package/components/form/ArrayList.vue +1 -1
  28. package/components/form/KeyValue.vue +3 -2
  29. package/components/form/Labels.vue +34 -14
  30. package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
  31. package/components/form/NameNsDescription.vue +1 -1
  32. package/components/form/PlusMinus.vue +2 -2
  33. package/components/form/Probe.vue +1 -1
  34. package/components/form/ProjectMemberEditor.vue +8 -4
  35. package/components/form/ResourceQuota/NamespaceRow.vue +1 -1
  36. package/components/form/ServicePorts.vue +2 -2
  37. package/components/form/Tolerations.vue +30 -3
  38. package/components/form/WorkloadPorts.vue +2 -1
  39. package/components/form/__tests__/KeyValue.test.ts +17 -0
  40. package/components/formatter/ClusterLink.vue +3 -3
  41. package/components/formatter/LiveDate.vue +1 -1
  42. package/components/formatter/PodImages.vue +1 -1
  43. package/components/formatter/RKETemplateName.vue +1 -1
  44. package/components/formatter/Shortened.vue +1 -1
  45. package/components/nav/Header.vue +7 -7
  46. package/components/nav/NamespaceFilter.vue +103 -54
  47. package/config/labels-annotations.js +8 -5
  48. package/config/settings.ts +2 -5
  49. package/config/types.js +6 -4
  50. package/core/plugin-routes.ts +26 -7
  51. package/core/plugins-loader.js +2 -0
  52. package/detail/provisioning.cattle.io.cluster.vue +4 -4
  53. package/edit/cis.cattle.io.clusterscan.vue +1 -1
  54. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +19 -149
  55. package/edit/logging-flow/index.vue +2 -2
  56. package/edit/logging.banzaicloud.io.output/providers/elasticsearch.vue +12 -0
  57. package/edit/logging.banzaicloud.io.output/providers/opensearch.vue +12 -0
  58. package/edit/management.cattle.io.project.vue +7 -0
  59. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +1 -1
  60. package/edit/monitoring.coreos.com.alertmanagerconfig/routeConfig.vue +2 -2
  61. package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +11 -8
  62. package/edit/networking.k8s.io.networkpolicy/PolicyRule.vue +2 -2
  63. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +12 -4
  64. package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.spec.ts +140 -0
  65. package/edit/networking.k8s.io.networkpolicy/__tests__/utils/mock.json +158 -0
  66. package/edit/networking.k8s.io.networkpolicy/__tests__/utils/selectors.ts +45 -0
  67. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -1
  68. package/edit/provisioning.cattle.io.cluster/AgentConfiguration.vue +1 -1
  69. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +1 -1
  70. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +1 -1
  71. package/edit/provisioning.cattle.io.cluster/RegistryMirrors.vue +2 -2
  72. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +143 -169
  73. package/edit/provisioning.cattle.io.cluster/rke2.vue +15 -6
  74. package/edit/resources.cattle.io.restore.vue +2 -2
  75. package/edit/service.vue +22 -3
  76. package/edit/storage.k8s.io.storageclass/index.vue +1 -1
  77. package/edit/workload/Job.vue +2 -2
  78. package/edit/workload/index.vue +1 -1
  79. package/edit/workload/mixins/workload.js +7 -1
  80. package/edit/workload/storage/__tests__/Storage.test.ts +84 -5
  81. package/initialize/index.js +1 -0
  82. package/layouts/default.vue +1 -1
  83. package/mixins/resource-fetch-namespaced.js +19 -27
  84. package/mixins/resource-fetch.js +0 -5
  85. package/models/__tests__/namespace.test.ts +125 -0
  86. package/models/management.cattle.io.project.js +6 -1
  87. package/models/persistentvolume.js +1 -1
  88. package/models/workload.service.js +22 -7
  89. package/package.json +17 -5
  90. package/pages/auth/login.vue +46 -49
  91. package/pages/c/_cluster/apps/charts/chart.vue +1 -1
  92. package/pages/c/_cluster/apps/charts/install.vue +42 -51
  93. package/pages/c/_cluster/explorer/index.vue +1 -1
  94. package/pages/c/_cluster/monitoring/index.vue +1 -1
  95. package/pages/c/_cluster/settings/performance.vue +53 -18
  96. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
  97. package/pages/c/_cluster/uiplugins/index.vue +16 -5
  98. package/pages/home.vue +1 -1
  99. package/pkg/vue.config.js +1 -0
  100. package/plugins/clean-html-directive.js +1 -1
  101. package/plugins/clean-tooltip-directive.js +33 -0
  102. package/plugins/dashboard-store/actions.js +4 -2
  103. package/plugins/dashboard-store/getters.js +6 -0
  104. package/plugins/dashboard-store/mutations.js +2 -2
  105. package/plugins/plugin.js +6 -1
  106. package/plugins/steve/actions.js +1 -1
  107. package/plugins/steve/getters.js +14 -3
  108. package/plugins/steve/resourceWatcher.js +36 -62
  109. package/plugins/steve/subscribe.js +137 -21
  110. package/plugins/steve/worker/index.js +7 -1
  111. package/plugins/steve/worker/web-worker.advanced.js +26 -8
  112. package/plugins/steve/worker/web-worker.basic.js +23 -4
  113. package/rancher-components/components/Form/Checkbox/Checkbox.vue +2 -2
  114. package/rancher-components/components/Form/Radio/RadioGroup.vue +2 -2
  115. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +1 -1
  116. package/store/index.js +16 -61
  117. package/store/store-types.js +5 -0
  118. package/store/type-map.js +1 -1
  119. package/types/shell/index.d.ts +23 -7
  120. package/utils/__tests__/create-yaml.test.ts +63 -0
  121. package/utils/array.ts +4 -0
  122. package/utils/create-yaml.js +5 -5
  123. package/utils/namespace-filter.js +17 -5
  124. package/utils/projectAndNamespaceFiltering.utils.ts +62 -0
  125. package/utils/selector.js +6 -5
  126. package/utils/settings.ts +5 -7
  127. package/models/k8s.cni.cncf.io.networkattachmentdefinition.js +0 -93
@@ -65,11 +65,6 @@ export default {
65
65
  default: false
66
66
  },
67
67
 
68
- loadNamespace: {
69
- type: String,
70
- default: null
71
- },
72
-
73
68
  showIncrementalLoadingIndicator: {
74
69
  type: Boolean,
75
70
  default: false
@@ -183,7 +178,6 @@ export default {
183
178
  v-if="showIncrementalLoadingIndicator"
184
179
  :resources="loadResources"
185
180
  :indeterminate="loadIndeterminate"
186
- :namespace="loadNamespace"
187
181
  />
188
182
  </div>
189
183
  <div class="actions-container">
@@ -17,10 +17,6 @@ export default {
17
17
  type: Boolean,
18
18
  default: false,
19
19
  },
20
- namespace: {
21
- type: String,
22
- default: undefined
23
- },
24
20
  },
25
21
 
26
22
  data() {
@@ -44,10 +40,6 @@ export default {
44
40
  // Have we loaded all resources for the types that are needed
45
41
  haveAll() {
46
42
  return this.resources.reduce((acc, r) => {
47
- if (this.namespace) {
48
- return acc && this.$store.getters[`${ this.inStore }/haveAllNamespace`](r, this.namespace);
49
- }
50
-
51
43
  return acc && this.$store.getters[`${ this.inStore }/haveAll`](r);
52
44
  }, true);
53
45
  },
@@ -58,7 +50,7 @@ export default {
58
50
 
59
51
  return this.resources.reduce((acc, r) => {
60
52
  const resourceCounts = clusterCounts?.[0]?.counts?.[r];
61
- const resourceCount = this.namespace ? resourceCounts?.namespaces?.[this.namespace]?.count : resourceCounts?.summary?.count;
53
+ const resourceCount = resourceCounts?.summary?.count;
62
54
  const count = resourceCount || 0;
63
55
 
64
56
  return acc + count;
@@ -8,6 +8,7 @@ import IconMessage from '@shell/components/IconMessage.vue';
8
8
  import { ResourceListComponentName } from './resource-list.config';
9
9
  import { PanelLocation, ExtensionPoint } from '@shell/core/types';
10
10
  import ExtensionPanel from '@shell/components/ExtensionPanel';
11
+ import { sameContents } from 'utils/array';
11
12
 
12
13
  export default {
13
14
  name: ResourceListComponentName,
@@ -146,7 +147,11 @@ export default {
146
147
  *
147
148
  * This covers case 1
148
149
  */
149
- namespaceFilter(neu) {
150
+ namespaceFilter(neu, old) {
151
+ if (sameContents(neu, old)) {
152
+ return;
153
+ }
154
+
150
155
  if (neu && !this.hasFetch) {
151
156
  this.$fetchType(this.resource);
152
157
  }
@@ -176,10 +181,7 @@ export default {
176
181
  icon="icon-filter_alt"
177
182
  >
178
183
  <template #message>
179
- <span
180
- v-clean-html="t('resourceList.nsFiltering', { resource: $store.getters['type-map/labelFor'](schema, 2) || customTypeDisplay }, true)"
181
- class="filter"
182
- />
184
+ {{ t('resourceList.nsFiltering') }}
183
185
  </template>
184
186
  </IconMessage>
185
187
  <div v-else>
@@ -191,7 +193,6 @@ export default {
191
193
  :show-incremental-loading-indicator="showIncrementalLoadingIndicator"
192
194
  :load-resources="loadResources"
193
195
  :load-indeterminate="loadIndeterminate"
194
- :load-namespace="namespaceFilter"
195
196
  >
196
197
  <template slot="extraActions">
197
198
  <slot name="extraActions" />
@@ -176,7 +176,12 @@ export default {
176
176
  return acc;
177
177
  }, {});
178
178
 
179
- return { listGroups, listGroupMapped };
179
+ // Confirm which store we're in, if schema isn't available we're probably showing a list with different types
180
+ const inStore = this.schema?.id ? this.$store.getters['currentStore'](this.schema.id) : undefined;
181
+
182
+ return {
183
+ listGroups, listGroupMapped, inStore
184
+ };
180
185
  },
181
186
 
182
187
  computed: {
@@ -244,8 +249,13 @@ export default {
244
249
  filteredRows() {
245
250
  const isAll = this.$store.getters['isAllNamespaces'];
246
251
 
247
- // If the resources isn't namespaced or we want ALL of them, there's nothing to do.
248
- if ( !this.isNamespaced || (isAll && !this.currentProduct?.hideSystemResources) || this.ignoreFilter) {
252
+ // Do we need to filter by namespace like things?
253
+ if (
254
+ !this.isNamespaced || // Resource type isn't namespaced
255
+ this.ignoreFilter || // Component owner strictly states no filtering
256
+ (isAll && !this.currentProduct?.hideSystemResources) || // Need all
257
+ (this.inStore ? this.$store.getters[`${ this.inStore }/haveNamespace`](this.schema.id)?.length : false)// Store reports type has namespace filter, so rows already contain the correctly filtered resources
258
+ ) {
249
259
  return this.rows || [];
250
260
  }
251
261
 
@@ -240,12 +240,12 @@ export default {
240
240
  >
241
241
  <span
242
242
  v-if="col.sort"
243
- v-tooltip="tooltip(col)"
243
+ v-clean-tooltip="tooltip(col)"
244
244
  >
245
245
  <span v-clean-html="labelFor(col)" />
246
246
  <i
247
247
  v-show="hasAdvancedFiltering && !col.isFilter"
248
- v-tooltip="t('sortableTable.tableHeader.noFilter')"
248
+ v-clean-tooltip="t('sortableTable.tableHeader.noFilter')"
249
249
  class="icon icon-info not-filter-icon"
250
250
  />
251
251
  <span class="icon-stack">
@@ -262,7 +262,7 @@ export default {
262
262
  </span>
263
263
  <span
264
264
  v-else
265
- v-tooltip="tooltip(col)"
265
+ v-clean-tooltip="tooltip(col)"
266
266
  >{{ labelFor(col) }}</span>
267
267
  </div>
268
268
  </th>
@@ -924,7 +924,7 @@ export default {
924
924
  v-for="act in availableActions"
925
925
  :id="act.action"
926
926
  :key="act.action"
927
- v-tooltip="actionTooltip"
927
+ v-clean-tooltip="actionTooltip"
928
928
  type="button"
929
929
  class="btn role-primary"
930
930
  :class="{[bulkActionClass]:true}"
@@ -963,7 +963,7 @@ export default {
963
963
  v-for="act in hiddenActions"
964
964
  :key="act.action"
965
965
  v-close-popover
966
- v-tooltip="{
966
+ v-clean-tooltip="{
967
967
  content: actionTooltip,
968
968
  placement: 'right'
969
969
  }"
@@ -1021,7 +1021,7 @@ export default {
1021
1021
  <slot name="header-right" />
1022
1022
  <AsyncButton
1023
1023
  v-if="isTooManyItemsToAutoUpdate"
1024
- v-tooltip="t('performance.manualRefresh.buttonTooltip')"
1024
+ v-clean-tooltip="t('performance.manualRefresh.buttonTooltip')"
1025
1025
  class="manual-refresh"
1026
1026
  mode="refresh"
1027
1027
  :current-phase="currentPhase"
@@ -102,7 +102,7 @@ export default {
102
102
  {{ labelDisplay }}
103
103
  <i
104
104
  v-if="tooltip"
105
- v-tooltip="tooltip"
105
+ v-clean-tooltip="tooltip"
106
106
  class="icon icon-info icon-lg"
107
107
  />
108
108
  </h2>
@@ -255,7 +255,7 @@ export default {
255
255
  >{{ tab.badge }}</span>
256
256
  <i
257
257
  v-if="hasIcon(tab)"
258
- v-tooltip="t('validation.tab')"
258
+ v-clean-tooltip="t('validation.tab')"
259
259
  class="conditions-alert-icon icon-error"
260
260
  />
261
261
  </a>
@@ -468,8 +468,7 @@ $spacer: 10px;
468
468
  flex-direction: column;
469
469
  flex: 1;
470
470
  padding: 0;
471
- height: 100%;
472
- position: relative;
471
+ height: 0;
473
472
  justify-content: flex-start;
474
473
  }
475
474
 
@@ -641,13 +640,15 @@ $spacer: 10px;
641
640
  height: 0;
642
641
  overflow-y: auto;
643
642
  padding: 20px 2px 2px 2px; // Handle borders flush against edge
644
-
645
643
  display: flex;
646
644
  flex-direction: column;
647
645
 
648
646
  &__step {
647
+ overflow: hidden;
648
+ display: flex;
649
+ flex-direction: column;
650
+ height: 100%;
649
651
  flex: 1;
650
- overflow: auto;
651
652
  }
652
653
  }
653
654
 
@@ -656,7 +657,6 @@ $spacer: 10px;
656
657
  // Overrides outlet padding
657
658
  margin-left: -$space-m;
658
659
  margin-right: -$space-m;
659
- margin-bottom: -$space-m;
660
660
  padding: $space-s $space-m;
661
661
 
662
662
  display: flex;
@@ -664,7 +664,10 @@ $spacer: 10px;
664
664
  padding-top: $spacer;
665
665
 
666
666
  border-top: var(--header-border-size) solid var(--header-border);
667
-
667
+ position: absolute;
668
+ bottom: 0;
669
+ width: 100%;
670
+ background: var(--body-bg);
668
671
  .controls-steps {
669
672
 
670
673
  .btn {
@@ -10,6 +10,7 @@ describe('component: NamespaceFilter', () => {
10
10
  options: () => [],
11
11
  value: () => [],
12
12
  },
13
+ mocks: { $fetchState: { pending: false } },
13
14
  directives: { shortkey: () => jest.fn() }
14
15
  });
15
16
  const filter = wrapper.find(`[data-testid="namespaces-filter"]`);
@@ -25,7 +26,10 @@ describe('component: NamespaceFilter', () => {
25
26
  options: () => [],
26
27
  value: () => [],
27
28
  },
28
- mocks: { $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } } },
29
+ mocks: {
30
+ $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } },
31
+ $fetchState: { pending: false }
32
+ },
29
33
  directives: { shortkey: () => jest.fn() }
30
34
  });
31
35
  const element = wrapper.find(`[data-testid="namespaces-values-none"]`).element.textContent;
@@ -44,6 +48,7 @@ describe('component: NamespaceFilter', () => {
44
48
  kind: 'special',
45
49
  }]),
46
50
  },
51
+ mocks: { $fetchState: { pending: false } },
47
52
  directives: { shortkey: () => jest.fn() }
48
53
  });
49
54
 
@@ -61,7 +66,10 @@ describe('component: NamespaceFilter', () => {
61
66
  value: () => [{ label: text }],
62
67
  },
63
68
  directives: { shortkey: () => jest.fn() },
64
- mocks: { $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } } },
69
+ mocks: {
70
+ $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } },
71
+ $fetchState: { pending: false }
72
+ },
65
73
  });
66
74
 
67
75
  const element = wrapper.find(`[data-testid="namespaces-value-0"]`).element.textContent;
@@ -97,7 +105,8 @@ describe('component: NamespaceFilter', () => {
97
105
  'prefs/get': () => preferences,
98
106
  namespaceFilterMode: () => undefined,
99
107
  },
100
- }
108
+ },
109
+ $fetchState: { pending: false }
101
110
  },
102
111
  directives: { shortkey: () => jest.fn() }
103
112
  });
@@ -116,7 +125,10 @@ describe('component: NamespaceFilter', () => {
116
125
  options: () => [],
117
126
  value: () => [],
118
127
  },
119
- mocks: { $store: { getters: { 'i18n/t': () => '', namespaceFilterMode: () => undefined } } },
128
+ mocks: {
129
+ $store: { getters: { 'i18n/t': () => '', namespaceFilterMode: () => undefined } },
130
+ $fetchState: { pending: false }
131
+ },
120
132
  directives: { shortkey: () => jest.fn() }
121
133
  });
122
134
  const dropdown = wrapper.find(`[data-testid="namespaces-dropdown"]`);
@@ -135,7 +147,10 @@ describe('component: NamespaceFilter', () => {
135
147
  options: () => [],
136
148
  value: () => [],
137
149
  },
138
- mocks: { $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } } },
150
+ mocks: {
151
+ $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } },
152
+ $fetchState: { pending: false }
153
+ },
139
154
  directives: { shortkey: () => jest.fn() }
140
155
  });
141
156
  const dropdown = wrapper.find(`[data-testid="namespaces-dropdown"]`);
@@ -153,7 +168,10 @@ describe('component: NamespaceFilter', () => {
153
168
  options: () => [],
154
169
  value: () => [],
155
170
  },
156
- mocks: { $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } } },
171
+ mocks: {
172
+ $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } },
173
+ $fetchState: { pending: false }
174
+ },
157
175
  directives: { shortkey: () => jest.fn() }
158
176
  });
159
177
 
@@ -194,7 +212,8 @@ describe('component: NamespaceFilter', () => {
194
212
  $store: {
195
213
  getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined },
196
214
  dispatch: action
197
- }
215
+ },
216
+ $fetchState: { pending: false }
198
217
  },
199
218
  directives: { shortkey: () => jest.fn() }
200
219
  });
@@ -627,7 +627,7 @@ export default {
627
627
  <span class="text-label">
628
628
  {{ t('rbac.roletemplate.tabs.grantResources.tableHeaders.resources') }}
629
629
  <i
630
- v-tooltip="t('rbac.roletemplate.tabs.grantResources.resourceOptionInfo')"
630
+ v-clean-tooltip="t('rbac.roletemplate.tabs.grantResources.resourceOptionInfo')"
631
631
  class="icon icon-info"
632
632
  />
633
633
  <span
@@ -175,7 +175,7 @@ export default {
175
175
  <LabeledSelect
176
176
  ref="labeled-select"
177
177
  v-model="newValue"
178
- v-tooltip="{
178
+ v-clean-tooltip="{
179
179
  content: tooltipContent,
180
180
  placement: 'bottom',
181
181
  classes: ['select-principal-tooltip']
@@ -146,7 +146,7 @@ export default {
146
146
  {{ row.clusterInfo.ready }}/{{ row.clusterInfo.total }}
147
147
  <i
148
148
  v-if="!row.clusterInfo.total"
149
- v-tooltip.bottom="parseTargetMode(row)"
149
+ v-clean-tooltip.bottom="parseTargetMode(row)"
150
150
  class="icon icon-warning"
151
151
  />
152
152
  </span>
@@ -206,7 +206,7 @@ export default {
206
206
  {{ title }}
207
207
  <i
208
208
  v-if="showProtip"
209
- v-tooltip="protip"
209
+ v-clean-tooltip="protip"
210
210
  class="icon icon-info"
211
211
  />
212
212
  </h3>
@@ -555,7 +555,7 @@ export default {
555
555
  {{ title }}
556
556
  <i
557
557
  v-if="titleProtip"
558
- v-tooltip="titleProtip"
558
+ v-clean-tooltip="titleProtip"
559
559
  class="icon icon-info"
560
560
  />
561
561
  </h3>
@@ -570,7 +570,7 @@ export default {
570
570
  {{ keyLabel }}
571
571
  <i
572
572
  v-if="protip && !isView && addAllowed"
573
- v-tooltip="protip"
573
+ v-clean-tooltip="protip"
574
574
  class="icon icon-info"
575
575
  />
576
576
  </label>
@@ -660,6 +660,7 @@ export default {
660
660
  <CodeMirror
661
661
  v-else-if="valueMarkdownMultiline"
662
662
  ref="cm"
663
+ data-testid="code-mirror-multiline-field"
663
664
  :class="{['focus']: codeMirrorFocus[i]}"
664
665
  :value="row[valueName]"
665
666
  :as-text-area="true"
@@ -42,7 +42,17 @@ export default {
42
42
  annotationTitleTooltip: {
43
43
  type: String,
44
44
  default: '',
45
- }
45
+ },
46
+
47
+ showAnnotations: {
48
+ type: Boolean,
49
+ default: true,
50
+ },
51
+
52
+ showLabelTitle: {
53
+ type: Boolean,
54
+ default: true,
55
+ },
46
56
  },
47
57
 
48
58
  data() {
@@ -69,7 +79,7 @@ export default {
69
79
  <div :class="defaultSectionClass">
70
80
  <div class="labels">
71
81
  <div class="labels__header">
72
- <h3>
82
+ <h3 v-if="showLabelTitle">
73
83
  <t k="labels.labels.title" />
74
84
  </h3>
75
85
  <ToggleSwitch
@@ -83,22 +93,32 @@ export default {
83
93
  <t k="labels.labels.description" />
84
94
  </p>
85
95
  <div :class="columnsClass">
86
- <KeyValue
87
- key="labels"
88
- :value="value.labels"
89
- :protected-keys="value.systemLabels || []"
90
- :toggle-filter="toggler"
91
- :add-label="t('labels.addLabel')"
92
- :mode="mode"
93
- :read-allowed="false"
94
- :value-can-be-empty="true"
95
- @input="value.setLabels($event)"
96
- />
96
+ <slot
97
+ name="labels"
98
+ :toggler="toggler"
99
+ >
100
+ <template>
101
+ <KeyValue
102
+ key="labels"
103
+ :value="value.labels"
104
+ :protected-keys="value.systemLabels || []"
105
+ :toggle-filter="toggler"
106
+ :add-label="t('labels.addLabel')"
107
+ :mode="mode"
108
+ :read-allowed="false"
109
+ :value-can-be-empty="true"
110
+ @input="value.setLabels($event)"
111
+ />
112
+ </template>
113
+ </slot>
97
114
  </div>
98
115
  </div>
99
116
  </div>
100
117
  <div class="spacer" />
101
- <div :class="sectionClass">
118
+ <div
119
+ v-if="showAnnotations"
120
+ :class="sectionClass"
121
+ >
102
122
  <KeyValue
103
123
  key="annotations"
104
124
  :value="value.annotations"
@@ -278,7 +278,7 @@ export default {
278
278
  />
279
279
  <i
280
280
  v-if="permission.locked"
281
- v-tooltip="permission.tooltip"
281
+ v-clean-tooltip="permission.tooltip"
282
282
  class="icon icon-lock icon-fw"
283
283
  />
284
284
  </div>
@@ -390,7 +390,7 @@ export default {
390
390
  @click="cancelCreateNamespace"
391
391
  >
392
392
  <i
393
- v-tooltip="t('generic.cancel')"
393
+ v-clean-tooltip="t('generic.cancel')"
394
394
  class="icon icon-close align-value"
395
395
  />
396
396
  </button>
@@ -50,7 +50,7 @@ export default {
50
50
  class="label"
51
51
  >{{ label }} </span>
52
52
  <button
53
- v-tooltip="minusTooltip"
53
+ v-clean-tooltip="minusTooltip"
54
54
  :disabled="disabled || !canMinus"
55
55
  type="button"
56
56
  class="btn btn-sm role-secondary"
@@ -62,7 +62,7 @@ export default {
62
62
  {{ value }}
63
63
  </div>
64
64
  <button
65
- v-tooltip="plusTooltip"
65
+ v-clean-tooltip="plusTooltip"
66
66
  :disabled="disabled || !canPlus"
67
67
  type="button"
68
68
  class="btn btn-sm role-secondary"
@@ -149,7 +149,7 @@ export default {
149
149
  {{ label }}
150
150
  <i
151
151
  v-if="description"
152
- v-tooltip="description"
152
+ v-clean-tooltip="description"
153
153
  class="icon icon-info"
154
154
  />
155
155
  </h3>
@@ -7,6 +7,7 @@ import { Card } from '@components/Card';
7
7
  import { RadioGroup } from '@components/Form/Radio';
8
8
  import { Checkbox } from '@components/Form/Checkbox';
9
9
  import { DESCRIPTION } from '@shell/config/labels-annotations';
10
+ import DOMPurify from 'dompurify';
10
11
 
11
12
  export default {
12
13
  components: {
@@ -160,9 +161,9 @@ export default {
160
161
 
161
162
  options() {
162
163
  const customRoles = this.customRoles.map(role => ({
163
- label: role.nameDisplay,
164
- description: role.description || role.metadata?.annotations?.[DESCRIPTION] || this.t('projectMembers.projectPermissions.noDescription'),
165
- value: role.id
164
+ label: this.purifyOption(role.nameDisplay),
165
+ description: this.purifyOption(role.description || role.metadata?.annotations?.[DESCRIPTION] || this.t('projectMembers.projectPermissions.noDescription')),
166
+ value: this.purifyOption(role.id),
166
167
  }));
167
168
 
168
169
  return [
@@ -245,6 +246,9 @@ export default {
245
246
  }
246
247
 
247
248
  return [permissionGroup];
249
+ },
250
+ purifyOption(option) {
251
+ return DOMPurify.sanitize(option, { ALLOWED_TAGS: ['span'] });
248
252
  }
249
253
  }
250
254
  };
@@ -301,7 +305,7 @@ export default {
301
305
  />
302
306
  <i
303
307
  v-if="permission.locked"
304
- v-tooltip="permission.tooltip"
308
+ v-clean-tooltip="permission.tooltip"
305
309
  class="icon icon-lock icon-fw"
306
310
  />
307
311
  </div>
@@ -182,7 +182,7 @@ export default {
182
182
  />
183
183
  <div class="resource-availability mr-10">
184
184
  <PercentageBar
185
- v-tooltip="tooltip"
185
+ v-clean-tooltip="tooltip"
186
186
  class="percentage-bar"
187
187
  :value="percentageUsed"
188
188
  :slices="slices"
@@ -137,7 +137,7 @@ export default {
137
137
  <span class="port">
138
138
  <t k="servicePorts.rules.listening.label" />
139
139
  <i
140
- v-tooltip="t('servicesPage.listeningPorts')"
140
+ v-clean-tooltip="t('servicesPage.listeningPorts')"
141
141
  class="icon icon-info flex"
142
142
  />
143
143
  <span class="text-error">*</span>
@@ -151,7 +151,7 @@ export default {
151
151
  <span class="target-port">
152
152
  <t k="servicePorts.rules.target.label" />
153
153
  <i
154
- v-tooltip="t('servicesPage.targetPorts')"
154
+ v-clean-tooltip="t('servicesPage.targetPorts')"
155
155
  class="icon icon-info flex"
156
156
  />
157
157
  <span class="text-error">*</span>
@@ -27,7 +27,27 @@ export default {
27
27
  },
28
28
 
29
29
  data() {
30
- return { rules: [...this.value] };
30
+ const rules = [];
31
+
32
+ // on creation in agent configuration, the backend "eats"
33
+ // the empty "effect" string, which doesn't happen on edit
34
+ // just to make sure we populate it correcty, let's consider
35
+ // no prop "effect" as an empty string which means all
36
+ // https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#toleration-v1-core
37
+ if (this.value.length) {
38
+ this.value.forEach((v) => {
39
+ if (!Object.keys(v).includes('effect')) {
40
+ rules.push({
41
+ ...v,
42
+ effect: ''
43
+ });
44
+ } else {
45
+ rules.push(v);
46
+ }
47
+ });
48
+ }
49
+
50
+ return { rules };
31
51
  },
32
52
 
33
53
  computed: {
@@ -83,7 +103,7 @@ export default {
83
103
  return [
84
104
  {
85
105
  label: this.t('workload.scheduling.tolerations.effectOptions.all'),
86
- value: 'All'
106
+ value: ''
87
107
  },
88
108
  {
89
109
  label: this.t('workload.scheduling.tolerations.effectOptions.noSchedule'),
@@ -129,6 +149,13 @@ export default {
129
149
  newRule.value = null;
130
150
  }
131
151
 
152
+ // remove effect from payload sent upstream, as it's empty
153
+ // it should be null, but the Select input doesn't seem to like it
154
+ // so we keep it as '' and sanitize it here
155
+ if (newRule.effect === '') {
156
+ delete newRule.effect;
157
+ }
158
+
132
159
  return newRule;
133
160
  });
134
161
 
@@ -136,7 +163,7 @@ export default {
136
163
  },
137
164
 
138
165
  addToleration() {
139
- this.rules.push({ vKey: random32() });
166
+ this.rules.push({ vKey: random32(), effect: '' });
140
167
  },
141
168
 
142
169
  updateEffect(neu, rule) {