@rancher/shell 0.3.8 → 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 (145) hide show
  1. package/assets/translations/en-us.yaml +47 -26
  2. package/assets/translations/zh-hans.yaml +82 -16
  3. package/babel.config.js +17 -4
  4. package/chart/istio.vue +11 -11
  5. package/chart/rancher-backup/S3.vue +1 -1
  6. package/components/AsyncButton.vue +2 -2
  7. package/components/ButtonGroup.vue +1 -1
  8. package/components/CodeMirror.vue +146 -14
  9. package/components/CompoundStatusBadge.vue +1 -1
  10. package/components/ContainerResourceLimit.vue +14 -1
  11. package/components/CopyCode.vue +1 -1
  12. package/components/CruResource.vue +21 -5
  13. package/components/DetailTop.vue +1 -1
  14. package/components/ExplorerProjectsNamespaces.vue +8 -4
  15. package/components/GlobalRoleBindings.vue +1 -1
  16. package/components/GroupPanel.vue +57 -0
  17. package/components/HarvesterServiceAddOnConfig.vue +2 -117
  18. package/components/ResourceDetail/Masthead.vue +1 -1
  19. package/components/ResourceList/Masthead.vue +0 -6
  20. package/components/ResourceList/ResourceLoadingIndicator.vue +1 -9
  21. package/components/ResourceList/index.vue +7 -6
  22. package/components/ResourceTable.vue +13 -3
  23. package/components/SortableTable/THead.vue +3 -3
  24. package/components/SortableTable/index.vue +3 -3
  25. package/components/Tabbed/Tab.vue +1 -1
  26. package/components/Tabbed/index.vue +1 -1
  27. package/components/Wizard.vue +9 -6
  28. package/components/YamlEditor.vue +2 -2
  29. package/components/__tests__/NamespaceFilter.test.ts +26 -7
  30. package/components/auth/RoleDetailEdit.vue +1 -1
  31. package/components/auth/SelectPrincipal.vue +1 -1
  32. package/components/fleet/FleetRepos.vue +1 -1
  33. package/components/form/ArrayList.vue +2 -2
  34. package/components/form/KeyValue.vue +37 -3
  35. package/components/form/Labels.vue +34 -14
  36. package/components/form/MatchExpressions.vue +120 -21
  37. package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
  38. package/components/form/NameNsDescription.vue +1 -1
  39. package/components/form/NodeAffinity.vue +54 -4
  40. package/components/form/PlusMinus.vue +2 -2
  41. package/components/form/PodAffinity.vue +160 -47
  42. package/components/form/Probe.vue +1 -1
  43. package/components/form/ProjectMemberEditor.vue +8 -4
  44. package/components/form/ResourceQuota/NamespaceRow.vue +1 -1
  45. package/components/form/ServicePorts.vue +2 -2
  46. package/components/form/Tolerations.vue +70 -7
  47. package/components/form/WorkloadPorts.vue +2 -1
  48. package/components/form/__tests__/ArrayList.test.ts +3 -3
  49. package/components/form/__tests__/KeyValue.test.ts +17 -0
  50. package/components/form/__tests__/MatchExpressions.test.ts +1 -1
  51. package/components/formatter/ClusterLink.vue +3 -3
  52. package/components/formatter/LiveDate.vue +1 -1
  53. package/components/formatter/PodImages.vue +1 -1
  54. package/components/formatter/RKETemplateName.vue +1 -1
  55. package/components/formatter/Shortened.vue +1 -1
  56. package/components/nav/Header.vue +9 -7
  57. package/components/nav/NamespaceFilter.vue +103 -54
  58. package/config/labels-annotations.js +8 -5
  59. package/config/settings.ts +8 -6
  60. package/config/types.js +6 -4
  61. package/core/plugin-routes.ts +26 -7
  62. package/detail/provisioning.cattle.io.cluster.vue +4 -4
  63. package/edit/cis.cattle.io.clusterscan.vue +1 -1
  64. package/edit/configmap.vue +33 -6
  65. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +19 -149
  66. package/edit/logging-flow/index.vue +2 -2
  67. package/edit/logging.banzaicloud.io.output/providers/elasticsearch.vue +12 -0
  68. package/edit/logging.banzaicloud.io.output/providers/opensearch.vue +12 -0
  69. package/edit/management.cattle.io.project.vue +7 -0
  70. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +1 -1
  71. package/edit/monitoring.coreos.com.alertmanagerconfig/routeConfig.vue +2 -2
  72. package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +11 -8
  73. package/edit/networking.k8s.io.networkpolicy/PolicyRule.vue +2 -2
  74. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +12 -4
  75. package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.spec.ts +140 -0
  76. package/edit/networking.k8s.io.networkpolicy/__tests__/utils/mock.json +158 -0
  77. package/edit/networking.k8s.io.networkpolicy/__tests__/utils/selectors.ts +45 -0
  78. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -1
  79. package/edit/provisioning.cattle.io.cluster/AgentConfiguration.vue +326 -0
  80. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +1 -1
  81. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +1 -1
  82. package/edit/provisioning.cattle.io.cluster/RegistryMirrors.vue +2 -2
  83. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +143 -169
  84. package/edit/provisioning.cattle.io.cluster/index.vue +1 -0
  85. package/edit/provisioning.cattle.io.cluster/rke2.vue +75 -6
  86. package/edit/resources.cattle.io.restore.vue +2 -2
  87. package/edit/service.vue +22 -3
  88. package/edit/storage.k8s.io.storageclass/index.vue +1 -1
  89. package/edit/workload/Job.vue +2 -2
  90. package/edit/workload/index.vue +1 -1
  91. package/edit/workload/mixins/workload.js +7 -1
  92. package/edit/workload/storage/__tests__/Storage.test.ts +84 -5
  93. package/initialize/index.js +1 -0
  94. package/layouts/default.vue +1 -1
  95. package/mixins/chart.js +1 -1
  96. package/mixins/resource-fetch-namespaced.js +19 -27
  97. package/mixins/resource-fetch.js +0 -5
  98. package/models/__tests__/namespace.test.ts +125 -0
  99. package/models/batch.cronjob.js +18 -3
  100. package/models/management.cattle.io.project.js +6 -1
  101. package/models/persistentvolume.js +1 -1
  102. package/models/workload.js +1 -1
  103. package/models/workload.service.js +22 -7
  104. package/package.json +17 -6
  105. package/pages/auth/login.vue +47 -49
  106. package/pages/c/_cluster/apps/charts/chart.vue +1 -1
  107. package/pages/c/_cluster/apps/charts/install.vue +42 -51
  108. package/pages/c/_cluster/explorer/index.vue +1 -1
  109. package/pages/c/_cluster/monitoring/index.vue +1 -1
  110. package/pages/c/_cluster/settings/performance.vue +53 -18
  111. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
  112. package/pages/c/_cluster/uiplugins/index.vue +16 -5
  113. package/pages/home.vue +1 -1
  114. package/pages/prefs.vue +18 -2
  115. package/plugins/clean-html-directive.js +1 -1
  116. package/plugins/clean-tooltip-directive.js +33 -0
  117. package/plugins/codemirror.js +158 -0
  118. package/plugins/dashboard-store/actions.js +4 -2
  119. package/plugins/dashboard-store/getters.js +6 -0
  120. package/plugins/dashboard-store/mutations.js +2 -2
  121. package/plugins/plugin.js +6 -1
  122. package/plugins/steve/actions.js +1 -1
  123. package/plugins/steve/getters.js +14 -3
  124. package/plugins/steve/resourceWatcher.js +36 -62
  125. package/plugins/steve/subscribe.js +137 -21
  126. package/plugins/steve/worker/index.js +7 -1
  127. package/plugins/steve/worker/web-worker.advanced.js +26 -8
  128. package/plugins/steve/worker/web-worker.basic.js +23 -4
  129. package/public/index.html +1 -1
  130. package/rancher-components/components/Form/Checkbox/Checkbox.vue +2 -2
  131. package/rancher-components/components/Form/Radio/RadioGroup.vue +2 -2
  132. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +1 -1
  133. package/store/index.js +16 -61
  134. package/store/store-types.js +5 -0
  135. package/store/type-map.js +1 -1
  136. package/types/shell/index.d.ts +42 -7
  137. package/utils/__tests__/create-yaml.test.ts +63 -0
  138. package/utils/array.ts +4 -0
  139. package/utils/create-yaml.js +105 -8
  140. package/utils/namespace-filter.js +17 -5
  141. package/utils/projectAndNamespaceFiltering.utils.ts +62 -0
  142. package/utils/selector.js +6 -5
  143. package/utils/settings.ts +17 -7
  144. package/vue.config.js +2 -2
  145. 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 {
@@ -86,7 +86,7 @@ export default {
86
86
  },
87
87
 
88
88
  computed: {
89
- cmOptions() {
89
+ codeMirrorOptions() {
90
90
  const readOnly = this.editorMode === EDITOR_MODES.VIEW_CODE;
91
91
 
92
92
  const gutters = [];
@@ -228,7 +228,7 @@ export default {
228
228
  ref="cm"
229
229
  :class="{fill: true, scrolling: scrolling}"
230
230
  :value="curValue"
231
- :options="cmOptions"
231
+ :options="codeMirrorOptions"
232
232
  :data-testid="componentTestid + '-code-mirror'"
233
233
  @onInput="onInput"
234
234
  @onReady="onReady"
@@ -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>
@@ -224,7 +224,7 @@ export default {
224
224
  <div
225
225
  v-for="(row, idx) in rows"
226
226
  :key="idx"
227
- data-testid="array-list-box"
227
+ :data-testid="`array-list-box${ idx }`"
228
228
  class="box"
229
229
  >
230
230
  <slot
@@ -10,11 +10,13 @@ import Select from '@shell/components/form/Select';
10
10
  import FileSelector from '@shell/components/form/FileSelector';
11
11
  import { _EDIT, _VIEW } from '@shell/config/query-params';
12
12
  import { asciiLike } from '@shell/utils/string';
13
+ import CodeMirror from '@shell/components/CodeMirror';
13
14
 
14
15
  export default {
15
16
  name: 'KeyValue',
16
17
 
17
18
  components: {
19
+ CodeMirror,
18
20
  Select,
19
21
  TextAreaAutoGrow,
20
22
  FileSelector
@@ -139,6 +141,10 @@ export default {
139
141
  type: Boolean,
140
142
  default: false,
141
143
  },
144
+ valueMarkdownMultiline: {
145
+ type: Boolean,
146
+ default: false,
147
+ },
142
148
  valueMultiline: {
143
149
  type: Boolean,
144
150
  default: true,
@@ -245,7 +251,10 @@ export default {
245
251
  data() {
246
252
  const rows = this.getRows(this.value);
247
253
 
248
- return { rows };
254
+ return {
255
+ rows,
256
+ codeMirrorFocus: {},
257
+ };
249
258
  },
250
259
 
251
260
  computed: {
@@ -519,6 +528,19 @@ export default {
519
528
  return this.t('detailText.binary', { n }, true);
520
529
  },
521
530
  get,
531
+ /**
532
+ * Update 'rows' variable with the user's input and prevents to update queue before the row model is updated
533
+ */
534
+ onInputMarkdownMultiline(idx, value) {
535
+ this.rows = this.rows.map((row, i) => i === idx ? { ...row, value } : row);
536
+ this.queueUpdate();
537
+ },
538
+ /**
539
+ * Set focus on CodeMirror fields
540
+ */
541
+ onFocusMarkdownMultiline(idx, value) {
542
+ this.$set(this.codeMirrorFocus, idx, value);
543
+ }
522
544
  }
523
545
  };
524
546
  </script>
@@ -533,7 +555,7 @@ export default {
533
555
  {{ title }}
534
556
  <i
535
557
  v-if="titleProtip"
536
- v-tooltip="titleProtip"
558
+ v-clean-tooltip="titleProtip"
537
559
  class="icon icon-info"
538
560
  />
539
561
  </h3>
@@ -548,7 +570,7 @@ export default {
548
570
  {{ keyLabel }}
549
571
  <i
550
572
  v-if="protip && !isView && addAllowed"
551
- v-tooltip="protip"
573
+ v-clean-tooltip="protip"
552
574
  class="icon icon-info"
553
575
  />
554
576
  </label>
@@ -635,6 +657,17 @@ export default {
635
657
  <div v-else-if="row.binary">
636
658
  {{ binaryTextSize(row.value) }}
637
659
  </div>
660
+ <CodeMirror
661
+ v-else-if="valueMarkdownMultiline"
662
+ ref="cm"
663
+ data-testid="code-mirror-multiline-field"
664
+ :class="{['focus']: codeMirrorFocus[i]}"
665
+ :value="row[valueName]"
666
+ :as-text-area="true"
667
+ :mode="mode"
668
+ @onInput="onInputMarkdownMultiline(i, $event)"
669
+ @onFocus="onFocusMarkdownMultiline(i, $event)"
670
+ />
638
671
  <TextAreaAutoGrow
639
672
  v-else-if="valueMultiline"
640
673
  v-model="row[valueName]"
@@ -750,6 +783,7 @@ export default {
750
783
  &.value textarea{
751
784
  padding: 10px 10px 10px 10px;
752
785
  }
786
+
753
787
  .text-monospace:not(.conceal) {
754
788
  font-family: monospace, monospace;
755
789
  }
@@ -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"