@rancher/shell 3.0.9-rc.5 → 3.0.9-rc.6

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 (142) hide show
  1. package/assets/images/providers/oci-open-containers.svg +22 -0
  2. package/assets/images/providers/traefik.png +0 -0
  3. package/assets/styles/themes/_dark.scss +2 -0
  4. package/assets/styles/themes/_light.scss +2 -0
  5. package/assets/styles/themes/_modern.scss +6 -0
  6. package/assets/translations/en-us.yaml +129 -25
  7. package/components/CruResource.vue +3 -1
  8. package/components/ExplorerProjectsNamespaces.vue +12 -12
  9. package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +109 -0
  10. package/components/Resource/Detail/Card/StatusCard/index.vue +21 -4
  11. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +19 -2
  12. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +19 -11
  13. package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +12 -0
  14. package/components/Resource/Detail/ResourcePopover/index.vue +2 -0
  15. package/components/Resource/Detail/ResourceRow.vue +2 -2
  16. package/components/ResourceList/index.vue +7 -4
  17. package/components/Window/ContainerLogs.vue +48 -37
  18. package/components/fleet/FleetClusterTargets/TargetsList.vue +2 -2
  19. package/components/fleet/FleetClusterTargets/index.vue +6 -1
  20. package/components/fleet/GitRepoAdvancedTab.vue +333 -0
  21. package/components/fleet/GitRepoMetadataTab.vue +43 -0
  22. package/components/fleet/GitRepoRepositoryTab.vue +101 -0
  23. package/components/fleet/GitRepoTargetTab.vue +77 -0
  24. package/components/fleet/HelmOpAdvancedTab.vue +247 -0
  25. package/components/fleet/HelmOpChartTab.vue +158 -0
  26. package/components/fleet/HelmOpMetadataTab.vue +46 -0
  27. package/components/fleet/HelmOpTargetTab.vue +84 -0
  28. package/components/fleet/HelmOpValuesTab.vue +147 -0
  29. package/components/fleet/__tests__/FleetClusterTargets.test.ts +119 -70
  30. package/components/form/NodeScheduling.vue +81 -7
  31. package/components/form/PodAffinity.vue +1 -36
  32. package/components/form/ResourceLabeledSelect.vue +8 -4
  33. package/components/form/ResourceQuota/Namespace.vue +30 -9
  34. package/components/form/ResourceQuota/NamespaceRow.vue +25 -7
  35. package/components/form/ResourceQuota/Project.vue +140 -82
  36. package/components/form/ResourceQuota/ResourceQuotaEntry.vue +145 -0
  37. package/components/form/ResourceQuota/__tests__/Namespace.test.ts +307 -0
  38. package/components/form/ResourceQuota/__tests__/NamespaceRow.test.ts +281 -0
  39. package/components/form/ResourceQuota/__tests__/Project.test.ts +274 -27
  40. package/components/form/ResourceQuota/__tests__/ResourceQuotaEntry.test.ts +215 -0
  41. package/components/form/SchedulingCustomization.vue +14 -6
  42. package/components/form/SelectOrCreateAuthSecret.vue +107 -18
  43. package/components/form/__tests__/NodeScheduling.test.ts +12 -9
  44. package/components/form/__tests__/PodAffinity.test.ts +21 -2
  45. package/components/form/__tests__/SchedulingCustomization.test.ts +240 -0
  46. package/components/formatter/ClusterLink.vue +8 -0
  47. package/components/formatter/SecretOrigin.vue +79 -0
  48. package/config/labels-annotations.js +7 -6
  49. package/config/pagination-table-headers.js +6 -4
  50. package/config/product/explorer.js +1 -11
  51. package/config/query-params.js +3 -0
  52. package/config/settings.ts +15 -2
  53. package/config/table-headers.js +21 -17
  54. package/config/types.js +23 -8
  55. package/detail/workload/index.vue +11 -16
  56. package/dialog/DeactivateDriverDialog.vue +1 -1
  57. package/dialog/Ipv6NetworkingDialog.vue +156 -0
  58. package/dialog/ScalePoolDownDialog.vue +2 -2
  59. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -1
  60. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +1 -0
  61. package/edit/__tests__/management.cattle.io.project.test.js +56 -128
  62. package/edit/auth/oidc.vue +1 -1
  63. package/edit/catalog.cattle.io.clusterrepo.vue +155 -25
  64. package/edit/fleet.cattle.io.gitrepo.vue +153 -283
  65. package/edit/fleet.cattle.io.helmop.vue +190 -332
  66. package/edit/management.cattle.io.project.vue +5 -42
  67. package/edit/management.cattle.io.setting.vue +6 -0
  68. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +55 -24
  69. package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +1 -103
  70. package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +13 -1
  71. package/edit/provisioning.cattle.io.cluster/__tests__/rke2-fleet-cluster-agent.test.ts +283 -0
  72. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +65 -49
  73. package/edit/provisioning.cattle.io.cluster/ingress/IngressCards.vue +112 -0
  74. package/edit/provisioning.cattle.io.cluster/ingress/IngressConfiguration.vue +158 -0
  75. package/edit/provisioning.cattle.io.cluster/rke2.vue +171 -72
  76. package/edit/provisioning.cattle.io.cluster/shared.ts +36 -1
  77. package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +2 -1
  78. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +55 -7
  79. package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +319 -0
  80. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +2 -1
  81. package/edit/provisioning.cattle.io.cluster/tabs/etcd/__tests__/S3Config.test.ts +13 -1
  82. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +10 -44
  83. package/edit/secret/index.vue +1 -1
  84. package/edit/token.vue +68 -29
  85. package/edit/workload/__tests__/index.test.ts +2 -37
  86. package/edit/workload/index.vue +6 -2
  87. package/edit/workload/mixins/workload.js +0 -32
  88. package/list/__tests__/management.cattle.io.setting.test.ts +198 -0
  89. package/list/management.cattle.io.setting.vue +13 -0
  90. package/list/provisioning.cattle.io.cluster.vue +50 -1
  91. package/list/secret.vue +4 -9
  92. package/list/service.vue +6 -8
  93. package/machine-config/amazonec2.vue +11 -4
  94. package/machine-config/components/EC2Networking.vue +46 -30
  95. package/machine-config/components/__tests__/EC2Networking.test.ts +7 -7
  96. package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +0 -9
  97. package/machine-config/digitalocean.vue +3 -3
  98. package/models/__tests__/namespace.test.ts +11 -0
  99. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +96 -0
  100. package/models/__tests__/workload.test.ts +42 -1
  101. package/models/catalog.cattle.io.clusterrepo.js +30 -4
  102. package/models/ext.cattle.io.token.js +48 -0
  103. package/models/kontainerdriver.js +2 -2
  104. package/models/namespace.js +7 -1
  105. package/models/nodedriver.js +2 -2
  106. package/models/provisioning.cattle.io.cluster.js +28 -7
  107. package/models/secret.js +0 -17
  108. package/models/service.js +44 -1
  109. package/models/token.js +4 -0
  110. package/models/workload.js +12 -6
  111. package/package.json +1 -1
  112. package/pages/account/index.vue +96 -67
  113. package/pages/auth/setup.vue +5 -14
  114. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +4 -1
  115. package/pages/c/_cluster/apps/charts/index.vue +93 -4
  116. package/pages/c/_cluster/apps/charts/install.vue +317 -42
  117. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -4
  118. package/pages/c/_cluster/settings/index.vue +3 -1
  119. package/plugins/dashboard-store/__tests__/getters.test.ts +108 -0
  120. package/plugins/dashboard-store/__tests__/resource-class.test.ts +27 -0
  121. package/plugins/dashboard-store/actions.js +3 -8
  122. package/plugins/dashboard-store/getters.js +7 -5
  123. package/plugins/dashboard-store/mutations.js +4 -1
  124. package/plugins/dashboard-store/resource-class.js +3 -3
  125. package/plugins/steve/__tests__/steve-class.test.ts +102 -141
  126. package/plugins/steve/steve-class.js +12 -3
  127. package/plugins/steve/steve-pagination-utils.ts +6 -2
  128. package/rancher-components/RcIcon/types.ts +2 -0
  129. package/rancher-components/RcItemCard/RcItemCard.vue +64 -19
  130. package/store/prefs.js +3 -0
  131. package/types/aws-sdk.d.ts +121 -0
  132. package/types/resources/node.ts +15 -0
  133. package/types/shell/index.d.ts +536 -506
  134. package/types/store/pagination.types.ts +5 -5
  135. package/utils/__tests__/array.test.ts +1 -29
  136. package/utils/__tests__/cluster-agent-configuration.test.ts +203 -0
  137. package/utils/array.ts +0 -11
  138. package/utils/aws.ts +21 -0
  139. package/utils/cluster.js +22 -2
  140. package/utils/selector-typed.ts +1 -1
  141. package/components/__tests__/ProjectRow.test.ts +0 -206
  142. package/components/form/ResourceQuota/ProjectRow.vue +0 -277
@@ -68,6 +68,8 @@ describe('component: Workload', () => {
68
68
  $store: {
69
69
  getters: {
70
70
  'cluster/schemaFor': jest.fn(),
71
+ 'cluster/canList': jest.fn(),
72
+ currentStore: () => 'cluster',
71
73
  'type-map/labelFor': jest.fn(),
72
74
  'i18n/t': (text: string, v: {[key:string]: string}) => {
73
75
  return `${ text }, ${ Object.values(v || {}) }`;
@@ -99,42 +101,5 @@ describe('component: Workload', () => {
99
101
 
100
102
  expect(result).toStrictEqual(newMessage);
101
103
  });
102
-
103
- describe('secondaryResourceDataConfig', () => {
104
- it('should filter out nodes with control-plane or etcd taints from workerNodes parsingFunc', () => {
105
- const allNodeObjects = [
106
- {
107
- id: 'node-1',
108
- spec: { taints: [{ key: 'node-role.kubernetes.io/control-plane', effect: 'NoSchedule' }] }
109
- },
110
- {
111
- id: 'node-2',
112
- spec: { taints: [{ key: 'node-role.kubernetes.io/etcd', effect: 'NoSchedule' }] }
113
- },
114
- {
115
- id: 'node-3',
116
- spec: { taints: [{ key: 'node-role.kubernetes.io/worker', effect: 'NoSchedule' }] }
117
- },
118
- {
119
- id: 'node-4',
120
- spec: { taints: [] }
121
- },
122
- {
123
- id: 'node-5',
124
- spec: {}
125
- },
126
- {
127
- id: 'node-6',
128
- spec: null
129
- }
130
- ];
131
-
132
- const { data } = (Workload.mixins[2] as any).methods.secondaryResourceDataConfig.apply({ value: { metadata: { namespace: 'test' } } });
133
- const workerNodesParsingFunc = data.node.applyTo.find((r: any) => r.var === 'workerNodes').parsingFunc;
134
- const result = workerNodesParsingFunc(allNodeObjects);
135
-
136
- expect(result).toStrictEqual(['node-3', 'node-4', 'node-5', 'node-6']);
137
- });
138
- });
139
104
  });
140
105
  });
@@ -4,6 +4,7 @@ import FormValidation from '@shell/mixins/form-validation';
4
4
  import WorkLoadMixin from '@shell/edit/workload/mixins/workload';
5
5
  import { mapGetters } from 'vuex';
6
6
  import { FORM_TYPES } from '@shell/components/form/Security';
7
+ import { NODE } from '@shell/config/types';
7
8
 
8
9
  export default {
9
10
  name: 'Workload',
@@ -21,9 +22,13 @@ export default {
21
22
  },
22
23
  },
23
24
  data() {
25
+ const inStore = this.$store.getters['currentStore'](NODE);
26
+ const canNode = this.$store.getters[`${ inStore }/canList`](NODE);
27
+
24
28
  return {
25
29
  selectedName: null,
26
30
  errors: [],
31
+ canNode,
27
32
  FORM_TYPES
28
33
  };
29
34
  },
@@ -506,11 +511,11 @@ export default {
506
511
  <PodAffinity
507
512
  :mode="mode"
508
513
  :value="podTemplateSpec"
509
- :nodes="allNodeObjects"
510
514
  :loading="isLoadingSecondaryResources"
511
515
  />
512
516
  </Tab>
513
517
  <Tab
518
+ v-if="canNode"
514
519
  :label="t('workload.container.titles.nodeScheduling')"
515
520
  name="nodeScheduling-pod"
516
521
  :weight="tabWeightMap['nodeScheduling']"
@@ -518,7 +523,6 @@ export default {
518
523
  <NodeScheduling
519
524
  :mode="mode"
520
525
  :value="podTemplateSpec"
521
- :nodes="workerNodes"
522
526
  :loading="isLoadingSecondaryResources"
523
527
  />
524
528
  </Tab>
@@ -5,7 +5,6 @@ import {
5
5
  CONFIG_MAP,
6
6
  SECRET,
7
7
  WORKLOAD_TYPES,
8
- NODE,
9
8
  SERVICE,
10
9
  PVC,
11
10
  SERVICE_ACCOUNT,
@@ -263,9 +262,6 @@ export default {
263
262
  return {
264
263
  secondaryResourceData: this.secondaryResourceDataConfig(),
265
264
  namespacedConfigMaps: [],
266
- allNodes: null,
267
- workerNodes: null,
268
- allNodeObjects: [],
269
265
  namespacedSecrets: [],
270
266
  imagePullNamespacedSecrets: [],
271
267
  allServices: [],
@@ -690,34 +686,6 @@ export default {
690
686
  }
691
687
  ]
692
688
  },
693
- [NODE]: {
694
- applyTo: [
695
- { var: 'allNodeObjects' },
696
- {
697
- var: 'allNodes',
698
- parsingFunc: (data) => {
699
- return data.map((node) => node.id);
700
- }
701
- },
702
- {
703
- var: 'workerNodes',
704
- parsingFunc: (data) => {
705
- const keys = [
706
- `node-role.kubernetes.io/control-plane`,
707
- `node-role.kubernetes.io/etcd`
708
- ];
709
-
710
- return data
711
- .filter((node) => {
712
- const taints = node?.spec?.taints || [];
713
-
714
- return taints.every((taint) => !keys.includes(taint.key));
715
- })
716
- .map((node) => node.id);
717
- }
718
- },
719
- ]
720
- },
721
689
  [SERVICE]: {
722
690
  applyTo: [
723
691
  { var: 'allServices' },
@@ -0,0 +1,198 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { nextTick } from 'vue';
3
+ import ManagementSetting from '@shell/list/management.cattle.io.setting.vue';
4
+ import { SETTING } from '@shell/config/settings';
5
+
6
+ const mockStore = {
7
+ getters: {
8
+ 'prefs/get': () => false,
9
+ 'i18n/t': (key: string) => key,
10
+ },
11
+ dispatch: jest.fn()
12
+ };
13
+
14
+ const mockRoute = {
15
+ hash: '',
16
+ params: {}
17
+ };
18
+
19
+ const mockRouter = {
20
+ push: jest.fn(),
21
+ replace: jest.fn()
22
+ };
23
+
24
+ // Mock scrollIntoView
25
+ const mockScrollIntoView = jest.fn();
26
+
27
+ Object.defineProperty(Element.prototype, 'scrollIntoView', {
28
+ value: mockScrollIntoView,
29
+ writable: true
30
+ });
31
+
32
+ // Mock querySelector
33
+ const mockQuerySelector = jest.fn();
34
+
35
+ Object.defineProperty(document, 'querySelector', {
36
+ value: mockQuerySelector,
37
+ writable: true
38
+ });
39
+
40
+ describe('managementSetting - Scroll Behavior', () => {
41
+ let wrapper: any;
42
+
43
+ const createWrapper = (routeHash = '') => {
44
+ const route = { ...mockRoute, hash: routeHash };
45
+
46
+ return mount(ManagementSetting, {
47
+ global: {
48
+ mocks: {
49
+ $store: mockStore,
50
+ $route: route,
51
+ $router: mockRouter,
52
+ $fetchState: { pending: false }
53
+ },
54
+ stubs: {
55
+ Loading: true,
56
+ Banner: true,
57
+ Setting: true
58
+ }
59
+ }
60
+ });
61
+ };
62
+
63
+ beforeEach(() => {
64
+ jest.clearAllMocks();
65
+ mockScrollIntoView.mockClear();
66
+ mockQuerySelector.mockClear();
67
+
68
+ // Mock successful API response with cluster agent setting
69
+ mockStore.dispatch.mockResolvedValue([
70
+ {
71
+ id: SETTING.CLUSTER_AGENT_DEFAULT_PRIORITY_CLASS,
72
+ value: '{"enabled": true}',
73
+ default: '{"enabled": false}',
74
+ availableActions: ['edit']
75
+ },
76
+ {
77
+ id: SETTING.FLEET_AGENT_DEFAULT_PRIORITY_CLASS,
78
+ value: '{"enabled": true}',
79
+ default: '{"enabled": false}',
80
+ availableActions: ['edit']
81
+ }
82
+ ]);
83
+ });
84
+
85
+ afterEach(() => {
86
+ if (wrapper) {
87
+ wrapper.unmount();
88
+ }
89
+ });
90
+
91
+ it('should scroll to hash anchor after data is loaded', async() => {
92
+ const mockElement = document.createElement('div');
93
+
94
+ mockQuerySelector.mockReturnValue(mockElement);
95
+
96
+ wrapper = createWrapper('#cluster-agent-default-priority-class');
97
+
98
+ // Trigger fetch manually since we can't easily test the async fetch hook
99
+ await wrapper.vm.$options.fetch.call(wrapper.vm);
100
+ await nextTick();
101
+
102
+ expect(mockQuerySelector).toHaveBeenCalledWith('#cluster-agent-default-priority-class');
103
+ expect(mockScrollIntoView).toHaveBeenCalledWith({
104
+ behavior: 'smooth',
105
+ block: 'start'
106
+ });
107
+ });
108
+
109
+ it('should not scroll if hash is empty', async() => {
110
+ wrapper = createWrapper('');
111
+
112
+ await wrapper.vm.$options.fetch.call(wrapper.vm);
113
+ await nextTick();
114
+
115
+ expect(mockQuerySelector).not.toHaveBeenCalled();
116
+ expect(mockScrollIntoView).not.toHaveBeenCalled();
117
+ });
118
+
119
+ it('should not scroll if element is not found', async() => {
120
+ mockQuerySelector.mockReturnValue(null);
121
+
122
+ wrapper = createWrapper('#non-existent-element');
123
+
124
+ await wrapper.vm.$options.fetch.call(wrapper.vm);
125
+ await nextTick();
126
+
127
+ expect(mockQuerySelector).toHaveBeenCalledWith('#non-existent-element');
128
+ expect(mockScrollIntoView).not.toHaveBeenCalled();
129
+ });
130
+
131
+ it('should scroll to fleet agent setting hash', async() => {
132
+ const mockElement = document.createElement('div');
133
+
134
+ mockQuerySelector.mockReturnValue(mockElement);
135
+
136
+ wrapper = createWrapper('#fleet-agent-default-priority-class');
137
+
138
+ await wrapper.vm.$options.fetch.call(wrapper.vm);
139
+ await nextTick();
140
+
141
+ expect(mockQuerySelector).toHaveBeenCalledWith('#fleet-agent-default-priority-class');
142
+ expect(mockScrollIntoView).toHaveBeenCalledWith({
143
+ behavior: 'smooth',
144
+ block: 'start'
145
+ });
146
+ });
147
+
148
+ it('should handle hash with special characters', async() => {
149
+ const mockElement = document.createElement('div');
150
+
151
+ mockQuerySelector.mockReturnValue(mockElement);
152
+
153
+ wrapper = createWrapper('#setting-with-special-chars_123');
154
+
155
+ await wrapper.vm.$options.fetch.call(wrapper.vm);
156
+ await nextTick();
157
+
158
+ expect(mockQuerySelector).toHaveBeenCalledWith('#setting-with-special-chars_123');
159
+ expect(mockScrollIntoView).toHaveBeenCalledWith({
160
+ behavior: 'smooth',
161
+ block: 'start'
162
+ });
163
+ });
164
+
165
+ it('should render settings with correct IDs for anchors', async() => {
166
+ wrapper = createWrapper();
167
+
168
+ // Manually set the data to simulate successful fetch
169
+ wrapper.vm.settings = [
170
+ {
171
+ id: SETTING.CLUSTER_AGENT_DEFAULT_PRIORITY_CLASS,
172
+ description: 'test-description',
173
+ data: { value: 'test' },
174
+ customized: false,
175
+ fromEnv: false,
176
+ hasActions: true
177
+ }
178
+ ];
179
+ wrapper.vm.provisioningSettings = [
180
+ {
181
+ id: SETTING.FLEET_AGENT_DEFAULT_PRIORITY_CLASS,
182
+ description: 'test-description',
183
+ data: { value: 'test' },
184
+ customized: false,
185
+ fromEnv: false,
186
+ hasActions: true
187
+ }
188
+ ];
189
+
190
+ await nextTick();
191
+
192
+ const settingDivs = wrapper.findAll('div[id]');
193
+ const ids = settingDivs.map((div: any) => div.attributes('id'));
194
+
195
+ expect(ids).toContain(SETTING.CLUSTER_AGENT_DEFAULT_PRIORITY_CLASS);
196
+ expect(ids).toContain(SETTING.FLEET_AGENT_DEFAULT_PRIORITY_CLASS);
197
+ });
198
+ });
@@ -66,6 +66,17 @@ export default {
66
66
 
67
67
  this.settings = settings;
68
68
  this.provisioningSettings = provisioningSettings;
69
+
70
+ this.$nextTick(() => {
71
+ // Handle scrolling to hash anchor after data is loaded
72
+ if (this.$route.hash) {
73
+ const element = document.querySelector(this.$route.hash);
74
+
75
+ if (element) {
76
+ element.scrollIntoView({ behavior: 'smooth', block: 'start' });
77
+ }
78
+ }
79
+ });
69
80
  },
70
81
 
71
82
  data() {
@@ -89,6 +100,7 @@ export default {
89
100
  </Banner>
90
101
  <div
91
102
  v-for="(setting) in settings"
103
+ :id="setting.id"
92
104
  :key="setting.id"
93
105
  >
94
106
  <Setting
@@ -101,6 +113,7 @@ export default {
101
113
  </h2>
102
114
  <div
103
115
  v-for="(setting) in provisioningSettings"
116
+ :id="setting.id"
104
117
  :key="setting.id"
105
118
  >
106
119
  <Setting
@@ -167,6 +167,12 @@ export default {
167
167
 
168
168
  },
169
169
 
170
+ methods: {
171
+ getCustomDetailLink(cluster) {
172
+ return cluster.isCapiHybrid ? null : cluster.detailLocation;
173
+ }
174
+ },
175
+
170
176
  $loadingResources() {
171
177
  // results are filtered so we wouldn't get the correct count on indicator...
172
178
  return { loadIndeterminate: true };
@@ -211,7 +217,6 @@ export default {
211
217
  </router-link>
212
218
  </template>
213
219
  </Masthead>
214
-
215
220
  <ResourceTable
216
221
  :headers="headers"
217
222
  :table-actions="true"
@@ -221,6 +226,8 @@ export default {
221
226
  :use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
222
227
  :data-testid="'cluster-list'"
223
228
  :force-update-live-and-delayed="forceUpdateLiveAndDelayed"
229
+ :get-custom-detail-link="getCustomDetailLink"
230
+ :sub-rows="true"
224
231
  >
225
232
  <!-- Why are state column and subrow overwritten here? -->
226
233
  <!-- for rke1 clusters, where they try to use the mgmt cluster stateObj instead of prov cluster stateObj, -->
@@ -266,6 +273,48 @@ export default {
266
273
  {{ t('cluster.explore') }}
267
274
  </button>
268
275
  </template>
276
+ <template #additional-sub-row="{row, fullColspan, tableActions}">
277
+ <tr
278
+ class="capi-unsupported"
279
+ :class="{'has-description': !!row.stateDescription}"
280
+ >
281
+ <td
282
+ v-if="row.isCapiHybrid"
283
+ class="row-check"
284
+ />
285
+ <td
286
+ v-if="row.isCapiHybrid"
287
+ :data-testid="`capi-unsupported-warning-${row?.metadata?.name}`"
288
+ :colspan="fullColspan - (tableActions ? 1: 0)"
289
+ >
290
+ <div
291
+ class="text-warning"
292
+ :class="{'mt-5': !!row.stateDescription.trim()}"
293
+ >
294
+ <i class="icon icon-warning" />{{ t('cluster.capi.notSupported') }}
295
+ </div>
296
+ </td>
297
+ </tr>
298
+ </template>
269
299
  </ResourceTable>
270
300
  </div>
271
301
  </template>
302
+
303
+ <stye scoped lang="scss">
304
+ .capi-unsupported {
305
+ &.has-description {
306
+ border-bottom: none;
307
+ padding: 0px;
308
+ td {
309
+ padding-top: 0px;
310
+ }
311
+ }
312
+
313
+ & div {
314
+ & i {
315
+ margin-right: 0.1em;
316
+ }
317
+ display: flex;
318
+ }
319
+ }
320
+ </stye>
package/list/secret.vue CHANGED
@@ -7,8 +7,8 @@ import PaginatedResourceTable from '@shell/components/PaginatedResourceTable';
7
7
  import { TableColumn } from '@shell/types/store/type-map';
8
8
  import ResourceFetch from '@shell/mixins/resource-fetch';
9
9
  import { mapGetters } from 'vuex';
10
- import { SECRET_CLONE, SECRET_PROJECT_SCOPED } from '@shell/config/table-headers';
11
- import { STEVE_SECRET_CLONE } from '@shell/config/pagination-table-headers';
10
+ import { SECRET_ORIGIN } from '@shell/config/table-headers';
11
+ import { STEVE_SECRET_ORIGIN } from '@shell/config/pagination-table-headers';
12
12
 
13
13
  export default {
14
14
  name: 'ListSecret',
@@ -61,13 +61,8 @@ export default {
61
61
 
62
62
  if (this.canViewProjects) {
63
63
  // if the user can see projects, add a column to let them know if it's a secret from a project scoped secret
64
- headers.push(SECRET_CLONE);
65
- headersSSP.push(STEVE_SECRET_CLONE);
66
- if (this.currentCluster.isLocal) {
67
- // if the user is on the local cluster, add a column to let them know if it's a project scoped secret (from another cluster)
68
- headers.push(SECRET_PROJECT_SCOPED);
69
- headersSSP.push(SECRET_PROJECT_SCOPED);
70
- }
64
+ headers.push(SECRET_ORIGIN);
65
+ headersSSP.push(STEVE_SECRET_ORIGIN);
71
66
  }
72
67
 
73
68
  headers.push(this.namespacedHeaders[this.namespacedHeaders.length - 1]);
package/list/service.vue CHANGED
@@ -1,6 +1,6 @@
1
1
  <script>
2
2
  import PaginatedResourceTable from '@shell/components/PaginatedResourceTable';
3
- import { NODE } from '@shell/config/types';
3
+ import { fetchNodesForServiceTargets } from '@shell/models/service';
4
4
 
5
5
  export default {
6
6
  name: 'ListService',
@@ -27,13 +27,11 @@ export default {
27
27
  * of type PagTableFetchSecondaryResources
28
28
  */
29
29
  async fetchSecondaryResources(opts) {
30
- const inStore = this.$store.getters['currentStore']();
31
-
32
- if (this.$store.getters[`${ inStore }/schemaFor`](NODE)) {
33
- // fetch nodes before loading this page, as they may be referenced in the Target table column
34
- // shell/components/formatter/ServiceTargets.vue --> shell/components/formatter/Endpoints.vue --> Picks the first one that has a model's externalIp
35
- await this.$store.dispatch(`${ inStore }/findAll`, { type: NODE });
36
- }
30
+ // Nodes should be fetched because they may be referenced in the target column of a service list item.
31
+ await fetchNodesForServiceTargets({
32
+ $store: this.$store,
33
+ inStore: this.$store.getters['currentStore']()
34
+ });
37
35
  }
38
36
  }
39
37
  };
@@ -24,7 +24,7 @@ export default {
24
24
 
25
25
  mixins: [CreateEditView],
26
26
 
27
- emits: ['validationChanged', 'update:hasIpv6'],
27
+ emits: ['validationChanged', 'update:isIpv6', 'update:isDualStack'],
28
28
 
29
29
  props: {
30
30
  uuid: {
@@ -47,7 +47,12 @@ export default {
47
47
  default: false
48
48
  },
49
49
 
50
- hasIpv6: {
50
+ isIpv6: {
51
+ type: Boolean,
52
+ default: false
53
+ },
54
+
55
+ isDualStack: {
51
56
  type: Boolean,
52
57
  default: false
53
58
  },
@@ -386,10 +391,12 @@ export default {
386
391
  :zone="value.zone"
387
392
  :region="value.region"
388
393
  :machine-pools="machinePools"
389
- :has-ipv6="hasIpv6"
394
+ :is-ipv6="isIpv6"
395
+ :is-dual-stack="isDualStack"
390
396
  :disabled="disabled"
391
397
  :is-new="poolCreateMode"
392
- @update:has-ipv6="e=>$emit('update:hasIpv6', e)"
398
+ @update:is-ipv6="e=>$emit('update:isIpv6', e)"
399
+ @update:is-dual-stack="e=>$emit('update:isDualStack', e)"
393
400
  @validation-changed="e=>$emit('validationChanged',e)"
394
401
  />
395
402