@rancher/shell 3.0.2-rc.2 → 3.0.2-rc.3

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 (141) hide show
  1. package/assets/styles/base/_basic.scss +5 -7
  2. package/assets/styles/global/_button.scss +10 -0
  3. package/assets/styles/global/_tooltip.scss +2 -2
  4. package/assets/styles/themes/_dark.scss +14 -2
  5. package/assets/styles/themes/_light.scss +7 -2
  6. package/assets/styles/vendor/vue-select.scss +4 -0
  7. package/assets/translations/en-us.yaml +44 -5
  8. package/components/BannerGraphic.vue +0 -42
  9. package/components/ButtonMultiAction.vue +1 -1
  10. package/components/Carousel.vue +36 -29
  11. package/components/CommunityLinks.vue +6 -1
  12. package/components/GrowlManager.vue +9 -2
  13. package/components/LocaleSelector.vue +8 -1
  14. package/components/PaginatedResourceTable.vue +4 -7
  15. package/components/ProgressBarMulti.vue +14 -0
  16. package/components/Questions/Reference.vue +57 -28
  17. package/components/SelectIconGrid.vue +12 -1
  18. package/components/SideNav.vue +12 -38
  19. package/components/SortableTable/index.vue +1 -0
  20. package/components/Tabbed/index.vue +12 -1
  21. package/components/YamlEditor.vue +1 -0
  22. package/components/auth/Principal.vue +5 -3
  23. package/components/fleet/FleetClusters.vue +82 -1
  24. package/components/fleet/FleetRepos.vue +13 -30
  25. package/components/fleet/ForceDirectedTreeChart/index.vue +2 -2
  26. package/components/form/ChangePassword.vue +2 -0
  27. package/components/form/ColorInput.vue +24 -1
  28. package/components/form/FileSelector.vue +2 -0
  29. package/components/form/KeyValue.vue +230 -160
  30. package/components/form/LabeledSelect.vue +1 -1
  31. package/components/form/PlusMinus.vue +14 -2
  32. package/components/form/ResourceLabeledSelect.vue +13 -53
  33. package/components/form/ResourceSelector.vue +1 -0
  34. package/components/form/ResourceTabs/index.vue +79 -36
  35. package/components/form/SecretSelector.vue +2 -2
  36. package/components/form/__tests__/KeyValue.test.ts +1 -1
  37. package/components/formatter/FleetClusterSummaryGraph.vue +2 -2
  38. package/components/formatter/FleetSummaryGraph.vue +6 -7
  39. package/components/formatter/WorkloadHealthScale.vue +7 -0
  40. package/components/nav/Group.vue +30 -4
  41. package/components/nav/Header.vue +82 -114
  42. package/components/nav/HeaderPageActionMenu.vue +27 -131
  43. package/components/nav/NamespaceFilter.vue +1 -1
  44. package/components/nav/Type.vue +15 -0
  45. package/config/home-links.js +21 -13
  46. package/config/labels-annotations.js +2 -0
  47. package/config/page-actions.js +1 -0
  48. package/config/pagination-table-headers.js +15 -1
  49. package/config/product/explorer.js +7 -17
  50. package/config/table-headers.js +6 -0
  51. package/config/version.js +5 -1
  52. package/core/plugin.ts +41 -1
  53. package/core/plugins.js +125 -72
  54. package/core/types-provisioning.ts +91 -2
  55. package/core/types.ts +55 -0
  56. package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +12 -3
  57. package/detail/catalog.cattle.io.app.vue +1 -1
  58. package/detail/fleet.cattle.io.cluster.vue +3 -3
  59. package/detail/namespace.vue +13 -19
  60. package/detail/networking.k8s.io.ingress.vue +13 -53
  61. package/detail/provisioning.cattle.io.cluster.vue +12 -1
  62. package/detail/workload/index.vue +3 -3
  63. package/dialog/AddCustomBadgeDialog.vue +5 -1
  64. package/edit/auth/ldap/__tests__/config.test.ts +18 -0
  65. package/edit/auth/ldap/config.vue +24 -0
  66. package/edit/auth/saml.vue +8 -6
  67. package/edit/fleet.cattle.io.gitrepo.vue +7 -1
  68. package/edit/logging-flow/index.vue +4 -19
  69. package/edit/networking.k8s.io.ingress/index.vue +18 -65
  70. package/edit/networking.k8s.io.networkpolicy/index.vue +4 -5
  71. package/edit/provisioning.cattle.io.cluster/index.vue +13 -1
  72. package/edit/provisioning.cattle.io.cluster/rke2.vue +31 -115
  73. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +2 -2
  74. package/edit/provisioning.cattle.io.cluster/tabs/networking/ACE.vue +14 -28
  75. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +25 -12
  76. package/edit/service.vue +1 -2
  77. package/list/networking.k8s.io.ingress.vue +1 -1
  78. package/list/node.vue +15 -8
  79. package/list/persistentvolume.vue +12 -4
  80. package/list/service.vue +1 -1
  81. package/list/workload.vue +4 -0
  82. package/mixins/chart.js +4 -1
  83. package/models/catalog.cattle.io.app.js +3 -1
  84. package/models/catalog.cattle.io.clusterrepo.js +56 -7
  85. package/models/fleet.cattle.io.bundle.js +0 -11
  86. package/models/fleet.cattle.io.cluster.js +17 -1
  87. package/models/fleet.cattle.io.gitrepo.js +86 -50
  88. package/models/provisioning.cattle.io.cluster.js +47 -2
  89. package/models/service.js +1 -0
  90. package/models/workload.js +19 -1
  91. package/package.json +5 -4
  92. package/pages/c/_cluster/apps/charts/index.vue +4 -0
  93. package/pages/c/_cluster/explorer/ConfigBadge.vue +8 -7
  94. package/pages/c/_cluster/explorer/index.vue +13 -6
  95. package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +3 -3
  96. package/pages/c/_cluster/fleet/index.vue +75 -89
  97. package/pages/c/_cluster/settings/links.vue +2 -2
  98. package/pages/diagnostic.vue +17 -15
  99. package/pages/home.vue +32 -6
  100. package/plugins/clean-html.js +50 -0
  101. package/plugins/dashboard-store/resource-class.js +4 -0
  102. package/plugins/plugin.js +54 -49
  103. package/plugins/steve/mutations.js +1 -1
  104. package/plugins/steve/steve-class.js +8 -0
  105. package/plugins/steve/steve-pagination-utils.ts +3 -1
  106. package/rancher-components/Accordion/Accordion.vue +4 -4
  107. package/rancher-components/BadgeState/BadgeState.vue +7 -0
  108. package/rancher-components/Card/Card.vue +27 -1
  109. package/rancher-components/Form/Checkbox/Checkbox.vue +9 -2
  110. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
  111. package/rancher-components/Form/LabeledInput/LabeledInput.vue +18 -1
  112. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +39 -2
  113. package/rancher-components/RcButton/RcButton.vue +90 -0
  114. package/rancher-components/RcButton/index.ts +2 -0
  115. package/rancher-components/RcButton/types.ts +17 -0
  116. package/rancher-components/RcDropdown/RcDropdown.vue +111 -0
  117. package/rancher-components/RcDropdown/RcDropdownItem.vue +127 -0
  118. package/rancher-components/RcDropdown/RcDropdownSeparator.vue +6 -0
  119. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +43 -0
  120. package/rancher-components/RcDropdown/index.ts +4 -0
  121. package/rancher-components/RcDropdown/types.ts +22 -0
  122. package/rancher-components/RcDropdown/useDropdownCollection.ts +45 -0
  123. package/rancher-components/RcDropdown/useDropdownContext.ts +83 -0
  124. package/scripts/test-plugins-build.sh +2 -0
  125. package/scripts/typegen.sh +2 -0
  126. package/store/catalog.js +1 -1
  127. package/tsconfig.json +2 -1
  128. package/types/components/paginatedResourceTable.ts +25 -0
  129. package/types/components/resourceLabeledSelect.ts +48 -0
  130. package/types/resources/fleet.d.ts +17 -0
  131. package/types/shell/index.d.ts +61 -0
  132. package/utils/auth.js +5 -1
  133. package/utils/cluster.js +106 -0
  134. package/utils/fleet.ts +35 -3
  135. package/utils/ingress.ts +64 -0
  136. package/utils/uiplugins.ts +56 -44
  137. package/utils/validators/cron-schedule.js +7 -2
  138. package/utils/validators/formRules/__tests__/index.test.ts +53 -17
  139. package/utils/validators/formRules/index.ts +20 -5
  140. package/vue.config.js +1 -1
  141. package/components/RelatedWorkloadsTable.vue +0 -50
@@ -1,12 +1,10 @@
1
1
  <script>
2
2
  import { allHash } from '@shell/utils/promise';
3
- import { SECRET, SERVICE } from '@shell/config/types';
4
3
  import CreateEditView from '@shell/mixins/create-edit-view';
5
4
  import Rules from '@shell/edit/networking.k8s.io.ingress/Rules';
6
5
  import ResourceTabs from '@shell/components/form/ResourceTabs';
7
6
  import Tab from '@shell/components/Tabbed/Tab';
8
- import { SECRET_TYPES as TYPES } from '@shell/config/secret';
9
- import { FilterArgs, PaginationParamFilter } from '@shell/types/store/pagination.types';
7
+ import IngressDetailEditHelper from '@shell/utils/ingress';
10
8
 
11
9
  export default {
12
10
  name: 'CRUIngress',
@@ -18,76 +16,38 @@ export default {
18
16
  },
19
17
  mixins: [CreateEditView],
20
18
  async fetch() {
19
+ this.ingressHelper = new IngressDetailEditHelper({
20
+ $store: this.$store,
21
+ namespace: this.value.metadata.namespace
22
+ });
21
23
  const promises = {
22
- services: this.$store.dispatch('cluster/findAll', { type: SERVICE }),
24
+ services: this.ingressHelper.fetchServices(),
25
+ secrets: this.ingressHelper.fetchSecrets(),
23
26
  resourceFields: this.schema.fetchResourceFields(),
24
27
  };
25
28
 
26
- if (this.$store.getters[`cluster/paginationEnabled`](SECRET)) {
27
- const findPageArgs = { // Of type ActionFindPageArgs
28
- namespaced: this.value.metadata.namespace,
29
- pagination: new FilterArgs({
30
- filters: PaginationParamFilter.createSingleField({
31
- field: 'metadata.fields.1',
32
- value: TYPES.TLS
33
- })
34
- }),
35
- };
36
-
37
- promises.filteredSecrets = this.$store.dispatch(`cluster/findPage`, { type: SECRET, opt: findPageArgs });
38
- } else {
39
- promises.secrets = this.$store.dispatch('cluster/findAll', { type: SECRET });
40
- }
41
29
  const hash = await allHash(promises);
42
30
 
43
- this.allServices = hash.services;
44
- this.allSecrets = hash.secrets;
45
- this.filteredSecrets = hash.filteredSecrets;
31
+ this.services = hash.services;
32
+ this.secrets = hash.secrets;
46
33
  },
47
34
  data() {
48
35
  return {
49
- allSecrets: null,
50
- filteredSecrets: null,
51
- allServices: [],
36
+ secrets: [],
37
+ services: [],
52
38
  };
53
39
  },
54
40
  computed: {
55
41
  serviceTargets() {
56
- return this.filterByCurrentResourceNamespace(this.allServices)
57
- .map((service) => ({
58
- label: service.metadata.name,
59
- value: service.metadata.name,
60
- ports: service.spec.ports?.map((p) => p.port)
61
- }));
42
+ return this.ingressHelper.findAndMapServiceTargets(this.services);
62
43
  },
63
44
  firstTabLabel() {
64
45
  return this.isView ? this.t('ingress.rulesAndCertificates.title') : this.t('ingress.rules.title');
65
46
  },
66
47
  certificates() {
67
- let filteredSecrets;
68
-
69
- if (this.filteredSecrets) {
70
- filteredSecrets = this.filteredSecrets;
71
- } else if (this.allSecrets ) {
72
- filteredSecrets = this.filterByCurrentResourceNamespace(this.allSecrets.filter((secret) => secret._type === TYPES.TLS));
73
- } else {
74
- return [];
75
- }
76
-
77
- return filteredSecrets.map((secret) => {
78
- const { id } = secret;
79
-
80
- return id.slice(id.indexOf('/') + 1);
81
- });
48
+ return this.ingressHelper.findAndMapCerts(this.secrets);
82
49
  },
83
50
  },
84
- methods: {
85
- filterByCurrentResourceNamespace(resources) {
86
- return resources.filter((resource) => {
87
- return resource.metadata.namespace === this.value.metadata.namespace;
88
- });
89
- }
90
- }
91
51
  };
92
52
  </script>
93
53
  <template>
@@ -84,6 +84,7 @@ export default {
84
84
  async fetch() {
85
85
  await this.value.waitForProvisioner();
86
86
 
87
+ // Support for the 'provisioner' extension
87
88
  const extClass = this.$plugin.getDynamic('provisioner', this.value.machineProvider);
88
89
 
89
90
  if (extClass) {
@@ -94,6 +95,7 @@ export default {
94
95
  $plugin: this.$store.app.$plugin,
95
96
  $t: this.t
96
97
  });
98
+
97
99
  this.extDetailTabs = {
98
100
  ...this.extDetailTabs,
99
101
  ...this.extProvider.detailTabs
@@ -101,6 +103,15 @@ export default {
101
103
  this.extCustomParams = { provider: this.value.machineProvider };
102
104
  }
103
105
 
106
+ // Support for a model extension
107
+ if (this.value.customProvisionerHelper) {
108
+ this.extDetailTabs = {
109
+ ...this.extDetailTabs,
110
+ ...this.value.customProvisionerHelper.detailTabs
111
+ };
112
+ this.extCustomParams = { provider: this.value.machineProvider };
113
+ }
114
+
104
115
  const schema = this.$store.getters[`management/schemaFor`](CAPI.RANCHER_CLUSTER);
105
116
  const fetchOne = { schemaDefinitions: schema.fetchResourceFields() };
106
117
 
@@ -379,7 +390,7 @@ export default {
379
390
  },
380
391
 
381
392
  showNodes() {
382
- return !this.showMachines && this.haveNodes && !!this.nodes.length;
393
+ return !this.showMachines && this.haveNodes && !!this.nodes.length && this.extDetailTabs.machines;
383
394
  },
384
395
 
385
396
  showSnapshots() {
@@ -47,8 +47,9 @@ export default {
47
47
  } catch {}
48
48
 
49
49
  const hash = {
50
- // See https://github.com/rancher/dashboard/issues/10417, all pods bad, come from a locally applied selector in the workload model
50
+ // Used in conjunction with `matches/match/label selectors`. Requires https://github.com/rancher/dashboard/issues/10417 to fix
51
51
  allPods: this.$store.dispatch('cluster/findAll', { type: POD }),
52
+ // Used in conjunction with `matches/match/label selectors`. Requires https://github.com/rancher/dashboard/issues/10417 to fix
52
53
  allServices: this.$store.dispatch('cluster/findAll', { type: SERVICE }),
53
54
  allIngresses: this.$store.dispatch('cluster/findAll', { type: INGRESS }),
54
55
  // Nodes should be fetched because they may be referenced in the target
@@ -57,7 +58,7 @@ export default {
57
58
  };
58
59
 
59
60
  if (this.value.type === WORKLOAD_TYPES.CRON_JOB) {
60
- hash.allJobs = this.$store.dispatch('cluster/findAll', { type: WORKLOAD_TYPES.JOB });
61
+ hash.jobs = this.value.matchingJobs();
61
62
  }
62
63
  const res = await allHash(hash);
63
64
 
@@ -91,7 +92,6 @@ export default {
91
92
  allIngresses: [],
92
93
  matchingServices: [],
93
94
  matchingIngresses: [],
94
- allJobs: [],
95
95
  allNodes: [],
96
96
  WORKLOAD_METRICS_DETAIL_URL,
97
97
  WORKLOAD_METRICS_SUMMARY_URL,
@@ -213,6 +213,7 @@ export default {
213
213
  <Card
214
214
  class="prompt-badge"
215
215
  :show-highlight-border="false"
216
+ :trigger-focus-trap="true"
216
217
  >
217
218
  <template #title>
218
219
  <h4 class="text-default-text">
@@ -258,7 +259,6 @@ export default {
258
259
  <Checkbox
259
260
  v-model:value="badgeAsIcon"
260
261
  :label="t('clusterBadge.modal.badgeAsIcon')"
261
-
262
262
  :tooltip="t('clusterBadge.modal.maxCharsTooltip')"
263
263
  />
264
264
 
@@ -312,7 +312,9 @@ export default {
312
312
  />
313
313
  <div class="buttons">
314
314
  <button
315
+ role="button"
315
316
  class="btn role-secondary mr-10"
317
+ :aria-label="t('generic.cancel')"
316
318
  @click="close"
317
319
  >
318
320
  {{ t('generic.cancel') }}
@@ -320,6 +322,8 @@ export default {
320
322
  <AsyncButton
321
323
  :action-label="t('clusterBadge.modal.buttonAction')"
322
324
  :disabled="!canSubmit"
325
+ role="button"
326
+ :aria-label="t('generic.cancel')"
323
327
  @click="apply"
324
328
  />
325
329
  </div>
@@ -0,0 +1,18 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import LDAPConfig from '@shell/edit/auth/ldap/config.vue';
3
+
4
+ describe('lDAP config', () => {
5
+ it.each([
6
+ 'openldap', 'freeipa'
7
+ ])('should display searchUsingServiceAccount checkbox if type %p', (type) => {
8
+ const wrapper = mount(LDAPConfig, {
9
+ propsData: {
10
+ value: {},
11
+ type,
12
+ }
13
+ });
14
+ const checkbox = wrapper.find('[data-testid="searchUsingServiceAccount"]');
15
+
16
+ expect(checkbox).toBeDefined();
17
+ });
18
+ });
@@ -11,6 +11,8 @@ const DEFAULT_TLS_PORT = 636;
11
11
 
12
12
  export const SHIBBOLETH = 'shibboleth';
13
13
  export const OKTA = 'okta';
14
+ export const OPEN_LDAP = 'openldap';
15
+ export const FREE_IPA = 'freeipa';
14
16
 
15
17
  export default {
16
18
  emits: ['update:value'],
@@ -64,6 +66,11 @@ export default {
64
66
  // Does the auth provider support LDAP for search in addition to SAML?
65
67
  isSamlProvider() {
66
68
  return this.type === SHIBBOLETH || this.type === OKTA;
69
+ },
70
+
71
+ // Allow to enable user search just for these providers
72
+ isSearchAllowed() {
73
+ return this.type === OPEN_LDAP || this.type === FREE_IPA;
67
74
  }
68
75
  },
69
76
 
@@ -226,6 +233,23 @@ export default {
226
233
  />
227
234
  </div>
228
235
  </div>
236
+
237
+ <div
238
+ v-if="isSearchAllowed"
239
+ class="row mb-20"
240
+ >
241
+ <div class="col">
242
+ <Checkbox
243
+ v-model:value="model.searchUsingServiceAccount"
244
+ :mode="mode"
245
+ data-testid="searchUsingServiceAccount"
246
+ class="full-height"
247
+ :label="t('authConfig.ldap.searchUsingServiceAccount.label')"
248
+ :tooltip="t('authConfig.ldap.searchUsingServiceAccount.tip')"
249
+ />
250
+ </div>
251
+ </div>
252
+
229
253
  <div class="row mb-20">
230
254
  <div class="col span-6">
231
255
  <LabeledInput
@@ -211,12 +211,14 @@ export default {
211
211
  </Banner>
212
212
 
213
213
  <table v-if="showLdapDetails && model.openLdapConfig">
214
- <tr><td>{{ t('authConfig.ldap.hostname.label') }}:</td><td>{{ ldapHosts }}</td></tr>
215
- <tr><td>{{ t('authConfig.ldap.port') }}:</td><td>{{ model.openLdapConfig.port }}</td></tr>
216
- <tr><td>{{ t('authConfig.ldap.protocol') }}:</td><td>{{ ldapProtocol }}</td></tr>
217
- <tr><td>{{ t('authConfig.ldap.serviceAccountDN') }}:</td><td>{{ model.openLdapConfig.serviceAccountDistinguishedName }}</td></tr>
218
- <tr><td>{{ t('authConfig.ldap.userSearchBase.label') }}:</td><td>{{ model.openLdapConfig.userSearchBase }}</td></tr>
219
- <tr><td>{{ t('authConfig.ldap.groupSearchBase.label') }}:</td><td>{{ model.openLdapConfig.groupSearchBase }}</td></tr>
214
+ <tbody>
215
+ <tr><td>{{ t('authConfig.ldap.hostname.label') }}:</td><td>{{ ldapHosts }}</td></tr>
216
+ <tr><td>{{ t('authConfig.ldap.port') }}:</td><td>{{ model.openLdapConfig.port }}</td></tr>
217
+ <tr><td>{{ t('authConfig.ldap.protocol') }}:</td><td>{{ ldapProtocol }}</td></tr>
218
+ <tr><td>{{ t('authConfig.ldap.serviceAccountDN') }}:</td><td>{{ model.openLdapConfig.serviceAccountDistinguishedName }}</td></tr>
219
+ <tr><td>{{ t('authConfig.ldap.userSearchBase.label') }}:</td><td>{{ model.openLdapConfig.userSearchBase }}</td></tr>
220
+ <tr><td>{{ t('authConfig.ldap.groupSearchBase.label') }}:</td><td>{{ model.openLdapConfig.groupSearchBase }}</td></tr>
221
+ </tbody>
220
222
  </table>
221
223
  </template>
222
224
  </AuthBanner>
@@ -153,7 +153,13 @@ export default {
153
153
  stepRepoInfo,
154
154
  stepTargetInfo,
155
155
  displayHelmRepoURLRegex: false,
156
- fvFormRuleSets: [{ path: 'spec.repo', rules: ['required'] }]
156
+ fvFormRuleSets: [{
157
+ path: 'spec.repo',
158
+ rules: [
159
+ 'required',
160
+ 'gitRepository'
161
+ ],
162
+ }]
157
163
  };
158
164
  },
159
165
 
@@ -6,14 +6,12 @@ import Loading from '@shell/components/Loading';
6
6
  import NameNsDescription from '@shell/components/form/NameNsDescription';
7
7
  import Tabbed from '@shell/components/Tabbed';
8
8
  import Tab from '@shell/components/Tabbed/Tab';
9
- import {
10
- LOGGING, NAMESPACE, NODE, POD, SCHEMA
11
- } from '@shell/config/types';
9
+ import { LOGGING, NAMESPACE, NODE, SCHEMA } from '@shell/config/types';
12
10
  import jsyaml from 'js-yaml';
13
11
  import { createYaml } from '@shell/utils/create-yaml';
14
12
  import YamlEditor, { EDITOR_MODES } from '@shell/components/YamlEditor';
15
13
  import { allHash } from '@shell/utils/promise';
16
- import { isArray, uniq } from '@shell/utils/array';
14
+ import { isArray } from '@shell/utils/array';
17
15
  import { matchRuleIsPopulated } from '@shell/models/logging.banzaicloud.io.flow';
18
16
  import LabeledSelect from '@shell/components/form/LabeledSelect';
19
17
  import { clone } from '@shell/utils/object';
@@ -67,7 +65,6 @@ export default {
67
65
  const hasAccessToOutputs = this.$store.getters[`${ inStore }/schemaFor`](LOGGING.OUTPUT);
68
66
  const hasAccessToNamespaces = this.$store.getters[`cluster/schemaFor`](NAMESPACE);
69
67
  const hasAccessToNodes = this.$store.getters[`${ inStore }/schemaFor`](NODE);
70
- const hasAccessToPods = this.$store.getters[`${ inStore }/schemaFor`](POD);
71
68
  const isFlow = this.value.type === LOGGING.FLOW;
72
69
 
73
70
  const getAllOrDefault = (type, hasAccess) => {
@@ -77,9 +74,10 @@ export default {
77
74
  const hash = await allHash({
78
75
  allOutputs: getAllOrDefault(LOGGING.OUTPUT, isFlow && hasAccessToOutputs),
79
76
  allClusterOutputs: getAllOrDefault(LOGGING.CLUSTER_OUTPUT, hasAccessToClusterOutputs),
77
+ // Can't remove allNamespaces yet given https://github.com/harvester/harvester/issues/7342 and
78
+ // https://github.com/harvester/harvester-ui-extension/blob/main/pkg/harvester/edit/harvesterhci.io.logging.clusteroutput.vue
80
79
  allNamespaces: getAllOrDefault(NAMESPACE, hasAccessToNamespaces),
81
80
  allNodes: getAllOrDefault(NODE, hasAccessToNodes),
82
- allPods: getAllOrDefault(POD, hasAccessToPods),
83
81
  });
84
82
 
85
83
  for ( const k of Object.keys(hash) ) {
@@ -134,7 +132,6 @@ export default {
134
132
  allClusterOutputs: null,
135
133
  allNamespaces: null,
136
134
  allNodes: null,
137
- allPods: null,
138
135
  filtersYaml,
139
136
  initialFiltersYaml: filtersYaml,
140
137
  globalOutputRefs,
@@ -239,18 +236,6 @@ export default {
239
236
  return out;
240
237
  },
241
238
 
242
- containerChoices() {
243
- const out = [];
244
-
245
- for ( const pod of this.allPods ) {
246
- for ( const c of (pod.spec?.containers || []) ) {
247
- out.push(c.name);
248
- }
249
- }
250
-
251
- return uniq(out).sort();
252
- },
253
-
254
239
  isHarvester() {
255
240
  return this.$store.getters['currentProduct'].inStore === VIRTUAL;
256
241
  },
@@ -1,6 +1,6 @@
1
1
  <script>
2
2
  import { allHash } from '@shell/utils/promise';
3
- import { SECRET, SERVICE, INGRESS_CLASS } from '@shell/config/types';
3
+ import { INGRESS_CLASS } from '@shell/config/types';
4
4
  import NameNsDescription from '@shell/components/form/NameNsDescription';
5
5
  import CreateEditView from '@shell/mixins/create-edit-view';
6
6
  import FormValidation from '@shell/mixins/form-validation';
@@ -10,13 +10,12 @@ import Labels from '@shell/components/form/Labels';
10
10
  import Error from '@shell/components/form/Error';
11
11
  import Tabbed from '@shell/components/Tabbed';
12
12
  import { get, set } from '@shell/utils/object';
13
- import { SECRET_TYPES as TYPES } from '@shell/config/secret';
14
13
  import DefaultBackend from './DefaultBackend';
15
14
  import Certificates from './Certificates';
16
15
  import Rules from './Rules';
17
16
  import IngressClass from './IngressClass';
18
17
  import Loading from '@shell/components/Loading';
19
- import { FilterArgs, PaginationParamFilter } from '@shell/types/store/pagination.types';
18
+ import IngressDetailEditHelper from '@shell/utils/ingress';
20
19
 
21
20
  export default {
22
21
  name: 'CRUIngress',
@@ -50,36 +49,32 @@ export default {
50
49
  },
51
50
 
52
51
  async fetch() {
52
+ this.ingressHelper = new IngressDetailEditHelper({
53
+ $store: this.$store,
54
+ namespace: this.value.metadata.namespace
55
+ });
56
+
53
57
  this.ingressClassSchema = this.$store.getters[`cluster/schemaFor`](INGRESS_CLASS);
54
58
 
55
59
  const promises = {
56
- services: this.$store.dispatch('cluster/findAll', { type: SERVICE }),
60
+ secrets: this.ingressHelper.fetchSecrets(),
61
+ services: this.ingressHelper.fetchServices(),
57
62
  ingressClasses: this.ingressClassSchema ? this.$store.dispatch('cluster/findAll', { type: INGRESS_CLASS }) : Promise.resolve([]),
58
63
  ingressResourceFields: this.schema.fetchResourceFields(),
59
64
  };
60
65
 
61
- this.filterByApi = this.$store.getters[`cluster/paginationEnabled`](SECRET);
62
-
63
- if (this.filterByApi) {
64
- promises.filteredSecrets = this.filterSecretsByApi();
65
- } else {
66
- promises.secrets = this.$store.dispatch('cluster/findAll', { type: SECRET });
67
- }
68
-
69
66
  const hash = await allHash(promises);
70
67
 
71
- this.allServices = hash.services;
72
- this.allSecrets = hash.secrets;
73
- this.filteredSecrets = hash.filteredSecrets;
68
+ this.secrets = hash.secrets;
69
+ this.services = hash.services;
74
70
  this.allIngressClasses = hash.ingressClasses;
75
71
  },
76
72
  data() {
77
73
  return {
78
74
  filterByApi: null,
79
75
  ingressClassSchema: null,
80
- allSecrets: null,
81
- filteredSecrets: null,
82
- allServices: [],
76
+ secrets: [],
77
+ services: [],
83
78
  allIngressClasses: [],
84
79
  fvFormRuleSets: [
85
80
  {
@@ -111,10 +106,9 @@ export default {
111
106
  },
112
107
 
113
108
  watch: {
114
- async 'value.metadata.namespace'() {
115
- if (this.filterByApi) {
116
- this.filteredSecrets = await this.filterSecretsByApi();
117
- }
109
+ async 'value.metadata.namespace'(neu) {
110
+ this.services = await this.ingressHelper.fetchServices({ namespace: neu });
111
+ this.secrets = await this.ingressHelper.fetchSecrets({ namespace: neu });
118
112
  }
119
113
  },
120
114
 
@@ -162,32 +156,13 @@ export default {
162
156
  return { name: [], port: [] };
163
157
  },
164
158
  serviceTargets() {
165
- return this.filterByCurrentResourceNamespace(this.allServices)
166
- .map((service) => ({
167
- label: service.metadata.name,
168
- value: service.metadata.name,
169
- ports: service.spec.ports?.map((p) => p.port)
170
- }));
159
+ return this.ingressHelper.findAndMapServiceTargets(this.services);
171
160
  },
172
161
  firstTabLabel() {
173
162
  return this.isView ? this.t('ingress.rulesAndCertificates.title') : this.t('ingress.rules.title');
174
163
  },
175
164
  certificates() {
176
- let filteredSecrets;
177
-
178
- if (this.filteredSecrets) {
179
- filteredSecrets = this.filteredSecrets;
180
- } else if (this.allSecrets ) {
181
- filteredSecrets = this.filterByCurrentResourceNamespace(this.allSecrets.filter((secret) => secret._type === TYPES.TLS));
182
- } else {
183
- return [];
184
- }
185
-
186
- return filteredSecrets.map((secret) => {
187
- const { id } = secret;
188
-
189
- return id.slice(id.indexOf('/') + 1);
190
- });
165
+ return this.ingressHelper.findAndMapCerts(this.secrets);
191
166
  },
192
167
  ingressClasses() {
193
168
  return this.allIngressClasses.map((ingressClass) => ({
@@ -210,28 +185,6 @@ export default {
210
185
  },
211
186
 
212
187
  methods: {
213
- filterSecretsByApi() {
214
- const findPageArgs = { // Of type ActionFindPageArgs
215
- namespaced: this.value.metadata.namespace,
216
- pagination: new FilterArgs({
217
- filters: PaginationParamFilter.createSingleField({
218
- field: 'metadata.fields.1',
219
- value: TYPES.TLS
220
- })
221
- }),
222
- };
223
-
224
- return this.$store.dispatch(`cluster/findPage`, { type: SECRET, opt: findPageArgs });
225
- },
226
-
227
- filterByCurrentResourceNamespace(resources) {
228
- // When configuring an Ingress, the options for Secrets and
229
- // default backend Services are limited to the namespace of the Ingress.
230
- return resources.filter((resource) => {
231
- return resource.metadata.namespace === this.value.metadata.namespace;
232
- });
233
- },
234
-
235
188
  willSave() {
236
189
  const backend = get(this.value.spec, this.value.defaultBackendPath);
237
190
  const serviceName = get(backend, this.value.serviceNamePath);
@@ -43,12 +43,12 @@ export default {
43
43
 
44
44
  async fetch() {
45
45
  const hash = await allHash({
46
- allPods: this.$store.dispatch('cluster/findAll', { type: POD }),
47
- allNamespaces: this.$store.dispatch('cluster/findAll', { type: NAMESPACE }),
46
+ allPods: this.$store.dispatch('cluster/findAll', { type: POD }), // Used in conjunction with `matches/match/label selectors`. Requires https://github.com/rancher/dashboard/issues/10417 to fix
47
+ allNamespaces: this.$store.dispatch('cluster/findAll', { type: NAMESPACE }), // Used in conjunction with `matches/match/label selectors`. Requires https://github.com/rancher/dashboard/issues/10417 to fix
48
48
  });
49
49
 
50
- this.allPods = hash.allPods;
51
- this.allNamespaces = hash.allNamespaces;
50
+ this.allPods = hash.allPods; // Used in matchingPods, and PolicyRules --> PolicyRule --> PolicyRuleTarget
51
+ this.allNamespaces = hash.allNamespaces; // Used in PolicyRules --> PolicyRule --> PolicyRuleTarget
52
52
 
53
53
  this.updateMatchingPods();
54
54
  },
@@ -147,7 +147,6 @@ export default {
147
147
 
148
148
  methods: {
149
149
  updateMatchingPods: throttle(function() {
150
- // See https://github.com/rancher/dashboard/issues/10417, all pods bad, need to replace local selector somehow
151
150
  const allInNamespace = this.allPods.filter((pod) => pod.metadata.namespace === this.value.metadata.namespace);
152
151
  const match = matching(allInNamespace, this.podSelectorExpressions);
153
152
  const matched = match.length || 0;
@@ -35,6 +35,8 @@ const SORT_GROUPS = {
35
35
 
36
36
  // uSed to proxy stylesheets for custom drivers that provide custom UI (RKE1)
37
37
  const PROXY_ENDPOINT = '/meta/proxy';
38
+ const IMPORTED = 'imported';
39
+ const LOCAL = 'local';
38
40
 
39
41
  export default {
40
42
  name: 'CruCluster',
@@ -171,7 +173,17 @@ export default {
171
173
  },
172
174
 
173
175
  data() {
174
- const subType = this.$route.query[SUB_TYPE] || null;
176
+ let subType = null;
177
+
178
+ subType = this.$route.query[SUB_TYPE] || null;
179
+
180
+ if ( this.$route.query[SUB_TYPE]) {
181
+ subType = this.$route.query[SUB_TYPE];
182
+ } else if (this.value.isImported) {
183
+ subType = IMPORTED;
184
+ } else if (this.value.isLocal) {
185
+ subType = LOCAL;
186
+ }
175
187
  const rkeType = this.$route.query[RKE_TYPE] || null;
176
188
  const chart = this.$route.query[CHART] || null;
177
189
  const isImport = this.realMode === _IMPORT;