@rancher/shell 3.0.5-rc.6 → 3.0.5-rc.8
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.
- package/assets/brand/classic/metadata.json +3 -0
- package/assets/styles/app.scss +1 -0
- package/assets/styles/base/_color.scss +16 -0
- package/assets/styles/base/_helpers.scss +10 -0
- package/assets/styles/base/_variables.scss +18 -12
- package/assets/styles/fonts/_icons.scss +1 -32
- package/assets/styles/global/_layout.scss +1 -1
- package/assets/styles/themes/_dark.scss +262 -258
- package/assets/styles/themes/_light.scss +538 -509
- package/assets/styles/themes/_modern.scss +914 -0
- package/assets/translations/en-us.yaml +110 -29
- package/chart/__tests__/S3.test.ts +2 -1
- package/cloud-credential/generic.vue +18 -10
- package/cloud-credential/harvester.vue +1 -9
- package/components/AdvancedSection.vue +8 -0
- package/components/ChartReadme.vue +17 -7
- package/components/CodeMirror.vue +1 -1
- package/components/Drawer/Chrome.vue +0 -1
- package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +27 -28
- package/components/Drawer/ResourceDetailDrawer/composables.ts +4 -24
- package/components/Drawer/ResourceDetailDrawer/index.vue +18 -4
- package/components/InstallHelmCharts.vue +656 -0
- package/components/LazyImage.vue +60 -4
- package/components/Loading.vue +1 -1
- package/components/LocaleSelector.vue +7 -2
- package/components/Markdown.vue +4 -0
- package/components/PaginatedResourceTable.vue +46 -1
- package/components/PromptRestore.vue +22 -44
- package/components/Resource/Detail/Masthead/composable.ts +16 -0
- package/components/Resource/Detail/Masthead/index.vue +37 -0
- package/components/Resource/Detail/Metadata/IdentifyingInformation/composable.ts +10 -2
- package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +26 -7
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +8 -1
- package/components/Resource/Detail/Metadata/KeyValue.vue +12 -10
- package/components/Resource/Detail/Metadata/Rectangle.vue +3 -1
- package/components/Resource/Detail/Metadata/__tests__/composables.test.ts +10 -17
- package/components/Resource/Detail/Metadata/composables.ts +9 -7
- package/components/Resource/Detail/Metadata/index.vue +17 -2
- package/components/Resource/Detail/Page.vue +35 -21
- package/components/Resource/Detail/SpacedRow.vue +1 -1
- package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +8 -9
- package/components/Resource/Detail/TitleBar/composables.ts +5 -5
- package/components/Resource/Detail/TitleBar/index.vue +12 -3
- package/components/ResourceDetail/Masthead/legacy.vue +1 -1
- package/components/ResourceDetail/index.vue +569 -72
- package/components/ResourceList/index.vue +1 -0
- package/components/ResourceTable.vue +6 -1
- package/components/ResourceYaml.vue +1 -1
- package/components/RichTranslation.vue +106 -0
- package/components/SlideInPanelManager.vue +13 -10
- package/components/SortableTable/index.vue +5 -5
- package/components/SortableTable/selection.js +0 -1
- package/components/Tabbed/index.vue +35 -4
- package/components/__tests__/LazyImage.spec.ts +121 -0
- package/components/__tests__/PromptRestore.test.ts +1 -65
- package/components/__tests__/RichTranslation.test.ts +115 -0
- package/components/fleet/FleetStatus.vue +4 -0
- package/components/fleet/dashboard/ResourcePanel.vue +2 -1
- package/components/form/ClusterAppearance.vue +5 -0
- package/components/form/FileImageSelector.vue +1 -1
- package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
- package/components/form/NameNsDescription.vue +1 -0
- package/components/form/Networking.vue +24 -19
- package/components/form/ProjectMemberEditor.vue +1 -1
- package/components/form/ResourceLabeledSelect.vue +22 -8
- package/components/form/ResourceTabs/index.vue +20 -0
- package/components/form/SecretSelector.vue +9 -0
- package/components/form/SelectOrCreateAuthSecret.vue +6 -3
- package/components/form/__tests__/Networking.test.ts +116 -0
- package/components/form/labeled-select-utils/labeled-select-pagination.ts +3 -38
- package/components/formatter/FleetApplicationSource.vue +25 -17
- package/components/formatter/PodImages.vue +1 -1
- package/components/formatter/__tests__/LiveDate.test.ts +10 -2
- package/components/google/AccountAccess.vue +44 -46
- package/components/nav/Favorite.vue +4 -0
- package/components/nav/Group.vue +4 -1
- package/components/nav/NotificationCenter/Notification.vue +1 -27
- package/components/nav/WindowManager/index.vue +3 -3
- package/composables/resources.ts +2 -2
- package/config/labels-annotations.js +3 -2
- package/config/pagination-table-headers.js +8 -1
- package/config/product/explorer.js +27 -2
- package/config/product/manager.js +0 -1
- package/config/query-params.js +10 -0
- package/config/router/routes.js +21 -1
- package/config/system-namespaces.js +1 -1
- package/config/table-headers.js +30 -1
- package/config/types.js +1 -1
- package/config/version.js +1 -1
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +11 -0
- package/detail/__tests__/workload.test.ts +164 -0
- package/detail/configmap.vue +33 -75
- package/detail/projectsecret.vue +11 -0
- package/detail/provisioning.cattle.io.cluster.vue +351 -369
- package/detail/secret.vue +49 -308
- package/detail/workload/index.vue +38 -21
- package/dialog/InstallExtensionDialog.vue +8 -5
- package/dialog/RotateEncryptionKeyDialog.vue +10 -30
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +224 -0
- package/edit/auth/ldap/__tests__/config.test.ts +14 -0
- package/edit/auth/ldap/config.vue +24 -0
- package/edit/compliance.cattle.io.clusterscan.vue +1 -1
- package/edit/configmap.vue +4 -1
- package/edit/fleet.cattle.io.gitrepo.vue +5 -6
- package/edit/fleet.cattle.io.helmop.vue +78 -56
- package/edit/logging.banzaicloud.io.output/index.vue +1 -1
- package/edit/logging.banzaicloud.io.output/providers/awsElasticsearch.vue +5 -6
- package/edit/networking.k8s.io.ingress/Certificate.vue +20 -22
- package/edit/networking.k8s.io.ingress/DefaultBackend.vue +8 -3
- package/edit/networking.k8s.io.ingress/Rule.vue +2 -5
- package/edit/networking.k8s.io.ingress/RulePath.vue +17 -11
- package/edit/networking.k8s.io.ingress/__tests__/Certificate.test.ts +165 -0
- package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +11 -10
- package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -3
- package/edit/networking.k8s.io.networkpolicy/index.vue +17 -17
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +3 -2
- package/edit/provisioning.cattle.io.cluster/rke2.vue +123 -61
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +9 -7
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +22 -13
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +10 -12
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +39 -38
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +41 -19
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +16 -3
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +32 -33
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryMirrors.vue +9 -10
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +1 -3
- package/edit/provisioning.cattle.io.cluster/tabs/upgrade/DrainOptions.vue +16 -9
- package/edit/secret/basic.vue +1 -0
- package/edit/secret/index.vue +126 -15
- package/edit/workload/index.vue +5 -14
- package/list/projectsecret.vue +345 -0
- package/list/provisioning.cattle.io.cluster.vue +1 -69
- package/list/secret.vue +109 -0
- package/machine-config/__tests__/vmwarevsphere.test.ts +5 -7
- package/machine-config/google.vue +9 -1
- package/machine-config/vmwarevsphere.vue +7 -17
- package/mixins/__tests__/brand.spec.ts +2 -2
- package/mixins/chart.js +0 -2
- package/mixins/create-edit-view/impl.js +10 -1
- package/mixins/resource-fetch-api-pagination.js +11 -12
- package/mixins/resource-fetch.js +3 -1
- package/models/__tests__/chart.test.ts +111 -80
- package/models/__tests__/fleet.cattle.io.helmop.test.ts +224 -0
- package/models/__tests__/node.test.ts +7 -63
- package/models/catalog.cattle.io.app.js +1 -1
- package/models/catalog.cattle.io.operation.js +1 -1
- package/models/chart.js +36 -20
- package/models/cloudcredential.js +2 -163
- package/models/cluster/node.js +7 -7
- package/models/cluster.x-k8s.io.machine.js +3 -3
- package/models/cluster.x-k8s.io.machinedeployment.js +11 -2
- package/models/compliance.cattle.io.clusterscan.js +2 -2
- package/models/configmap.js +4 -0
- package/models/constraints.gatekeeper.sh.constraint.js +1 -1
- package/models/fleet-application.js +0 -17
- package/models/fleet.cattle.io.cluster.js +2 -2
- package/models/fleet.cattle.io.gitrepo.js +15 -1
- package/models/fleet.cattle.io.helmop.js +26 -22
- package/models/management.cattle.io.setting.js +4 -0
- package/models/persistentvolumeclaim.js +1 -1
- package/models/pod.js +2 -2
- package/models/provisioning.cattle.io.cluster.js +39 -67
- package/models/rke.cattle.io.etcdsnapshot.js +1 -1
- package/models/secret.js +161 -2
- package/models/storage.k8s.io.storageclass.js +2 -2
- package/models/workload.js +3 -3
- package/package.json +11 -10
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +1 -0
- package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +4 -1
- package/pages/c/_cluster/apps/charts/__tests__/AppChartCardFooter.spec.js +41 -0
- package/pages/c/_cluster/apps/charts/chart.vue +422 -174
- package/pages/c/_cluster/apps/charts/index.vue +46 -35
- package/pages/c/_cluster/apps/charts/install.vue +1 -1
- package/pages/c/_cluster/explorer/projectsecret.vue +24 -0
- package/pages/c/_cluster/fleet/__tests__/index.test.ts +608 -314
- package/pages/c/_cluster/fleet/index.vue +103 -45
- package/pages/c/_cluster/manager/cloudCredential/index.vue +2 -59
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +10 -3
- package/pages/c/_cluster/uiplugins/index.vue +36 -25
- package/plugins/dashboard-store/__tests__/normalize.test.ts +223 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +191 -0
- package/plugins/dashboard-store/__tests__/utils/normalize-usecases.ts +1526 -0
- package/plugins/dashboard-store/actions.js +42 -22
- package/plugins/dashboard-store/normalize.js +29 -17
- package/plugins/dashboard-store/resource-class.js +83 -17
- package/plugins/steve/__tests__/getters.test.ts +1 -1
- package/plugins/steve/__tests__/subscribe.spec.ts +259 -1
- package/plugins/steve/getters.js +8 -2
- package/plugins/steve/resourceWatcher.js +10 -3
- package/plugins/steve/steve-pagination-utils.ts +14 -3
- package/plugins/steve/subscribe.js +192 -19
- package/plugins/steve/worker/web-worker.advanced.js +2 -0
- package/rancher-components/Card/Card.vue +0 -18
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.test.ts +15 -0
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +65 -0
- package/rancher-components/Pill/RcStatusBadge/index.ts +2 -0
- package/rancher-components/Pill/RcStatusBadge/types.ts +5 -0
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.test.ts +33 -0
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +75 -0
- package/rancher-components/Pill/RcStatusIndicator/index.ts +2 -0
- package/rancher-components/Pill/RcStatusIndicator/types.ts +7 -0
- package/rancher-components/Pill/types.ts +2 -0
- package/rancher-components/RcButton/RcButton.vue +1 -1
- package/rancher-components/RcDropdown/RcDropdown.test.ts +98 -0
- package/rancher-components/RcDropdown/RcDropdown.vue +5 -0
- package/rancher-components/RcDropdown/RcDropdownItem.vue +7 -1
- package/rancher-components/RcDropdown/RcDropdownItemCheckbox.vue +2 -1
- package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +2 -1
- package/rancher-components/RcDropdown/useDropdownContext.ts +21 -0
- package/rancher-components/RcDropdown/useDropdownItem.ts +30 -1
- package/rancher-components/RcItemCard/RcItemCard.test.ts +20 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +40 -6
- package/store/__tests__/catalog.test.ts +93 -1
- package/store/aws.js +19 -8
- package/store/catalog.js +8 -3
- package/types/kube/kube-api.ts +12 -0
- package/types/resources/settings.d.ts +1 -1
- package/types/shell/index.d.ts +643 -585
- package/types/store/pagination.types.ts +16 -6
- package/types/uiplugins.ts +73 -0
- package/utils/__tests__/back-off.test.ts +354 -0
- package/utils/__tests__/create-yaml.test.ts +235 -0
- package/utils/__tests__/kontainer.test.ts +19 -0
- package/utils/__tests__/uiplugins.test.ts +84 -0
- package/utils/back-off.ts +176 -0
- package/utils/create-yaml.js +103 -9
- package/utils/dynamic-importer.js +8 -0
- package/utils/kontainer.ts +3 -5
- package/utils/pagination-utils.ts +18 -0
- package/utils/style.ts +3 -0
- package/utils/uiplugins.ts +29 -2
- package/utils/validators/__tests__/setting.test.js +92 -0
- package/utils/validators/formRules/__tests__/index.test.ts +88 -7
- package/utils/validators/formRules/index.ts +83 -8
- package/utils/validators/setting.js +17 -0
- package/cloud-credential/__tests__/harvester.test.ts +0 -18
- package/components/ResourceDetail/__tests__/index.test.ts +0 -135
- package/components/ResourceDetail/legacy.vue +0 -562
- package/components/formatter/CloudCredExpired.vue +0 -69
- package/models/etcdbackup.js +0 -45
- package/pages/explorer/resource/detail/configmap.vue +0 -42
- package/pages/explorer/resource/detail/secret.vue +0 -50
- package/utils/aws.js +0 -0
|
@@ -106,57 +106,55 @@ export default defineComponent({
|
|
|
106
106
|
</script>
|
|
107
107
|
|
|
108
108
|
<template>
|
|
109
|
-
<div
|
|
109
|
+
<div
|
|
110
|
+
:class="{'showing-form': !credential}"
|
|
111
|
+
class="credential-project"
|
|
112
|
+
>
|
|
110
113
|
<div
|
|
111
|
-
|
|
112
|
-
class="
|
|
114
|
+
v-show="!!credential"
|
|
115
|
+
class="project mb-10"
|
|
113
116
|
>
|
|
114
|
-
<
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
label-key="gke.project.label"
|
|
122
|
-
required
|
|
123
|
-
@update:value="(val) => $emit('update:project', val.trim())"
|
|
124
|
-
/>
|
|
125
|
-
</div>
|
|
126
|
-
<div
|
|
127
|
-
:class="{'view': isView}"
|
|
128
|
-
class="select-credential-container mb-10"
|
|
129
|
-
>
|
|
130
|
-
<SelectCredential
|
|
131
|
-
:value="credential"
|
|
132
|
-
data-testid="crugke-select-credential"
|
|
133
|
-
:mode="(isView|| isAuthenticated) ? VIEW : CREATE"
|
|
134
|
-
provider="gcp"
|
|
135
|
-
:default-on-cancel="true"
|
|
136
|
-
:showing-form="!credential"
|
|
137
|
-
class="select-credential"
|
|
138
|
-
:cancel="()=>$emit('cancel-credential')"
|
|
139
|
-
@update:value="$emit('update:credential', $event)"
|
|
140
|
-
@credential-created="parseNewCredential"
|
|
141
|
-
/>
|
|
142
|
-
</div>
|
|
117
|
+
<LabeledInput
|
|
118
|
+
:disabled="isAuthenticated"
|
|
119
|
+
:value="project"
|
|
120
|
+
label-key="gke.project.label"
|
|
121
|
+
required
|
|
122
|
+
@update:value="(val) => $emit('update:project', val.trim())"
|
|
123
|
+
/>
|
|
143
124
|
</div>
|
|
144
125
|
<div
|
|
145
|
-
|
|
146
|
-
class="
|
|
126
|
+
:class="{'view': isView}"
|
|
127
|
+
class="select-credential-container"
|
|
147
128
|
>
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
129
|
+
<SelectCredential
|
|
130
|
+
:value="credential"
|
|
131
|
+
data-testid="crugke-select-credential"
|
|
132
|
+
:mode="(isView|| isAuthenticated) ? VIEW : CREATE"
|
|
133
|
+
provider="gcp"
|
|
134
|
+
:default-on-cancel="true"
|
|
135
|
+
:showing-form="!credential"
|
|
136
|
+
class="select-credential"
|
|
137
|
+
:cancel="()=>$emit('cancel-credential')"
|
|
138
|
+
@update:value="$emit('update:credential', $event)"
|
|
139
|
+
@credential-created="parseNewCredential"
|
|
140
|
+
/>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
<div
|
|
144
|
+
v-if="!isView && !isAuthenticated && !!credential"
|
|
145
|
+
class="row mt-10"
|
|
146
|
+
>
|
|
147
|
+
<div
|
|
148
|
+
v-show="!!credential"
|
|
149
|
+
class="auth-button-container mb-10"
|
|
150
|
+
>
|
|
151
|
+
<AsyncButton
|
|
152
|
+
:disabled="!credential || !project || isAuthenticated"
|
|
153
|
+
type="button"
|
|
154
|
+
class="btn"
|
|
155
|
+
mode="authenticate"
|
|
156
|
+
@click="testProjectId"
|
|
157
|
+
/>
|
|
160
158
|
</div>
|
|
161
159
|
</div>
|
|
162
160
|
</template>
|
package/components/nav/Group.vue
CHANGED
|
@@ -226,7 +226,10 @@ export default {
|
|
|
226
226
|
class="accordion"
|
|
227
227
|
:class="{[`depth-${depth}`]: true, 'expanded': isExpanded, 'has-children': hasChildren, 'group-highlight': isGroupActive }"
|
|
228
228
|
>
|
|
229
|
-
<div
|
|
229
|
+
<div
|
|
230
|
+
v-if="showHeader || (!onlyHasOverview && canCollapse)"
|
|
231
|
+
class="accordion-item"
|
|
232
|
+
>
|
|
230
233
|
<div
|
|
231
234
|
v-if="showHeader"
|
|
232
235
|
class="header"
|
|
@@ -31,7 +31,7 @@ const unreadCount = computed<number>(() => store.getters['notifications/unreadCo
|
|
|
31
31
|
const dateFormat = escapeHtml( store.getters['prefs/get'](DATE_FORMAT));
|
|
32
32
|
const timeFormat = escapeHtml( store.getters['prefs/get'](TIME_FORMAT));
|
|
33
33
|
|
|
34
|
-
const { close } = useDropdownItem();
|
|
34
|
+
const { close, scrollIntoView } = useDropdownItem();
|
|
35
35
|
|
|
36
36
|
// Outer element for the notification
|
|
37
37
|
const dropdownMenuItem = ref<HTMLElement>();
|
|
@@ -217,32 +217,6 @@ const findNewIndex = (shouldAdvance: boolean, activeIndex: number, itemsArr: Ele
|
|
|
217
217
|
|
|
218
218
|
return newIndex;
|
|
219
219
|
};
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Ensure we scroll the item into view smoothly
|
|
223
|
-
* @param event FocusIn Event
|
|
224
|
-
*/
|
|
225
|
-
const scrollIntoView = (event: Event) => {
|
|
226
|
-
const target = event.target;
|
|
227
|
-
|
|
228
|
-
if (target instanceof HTMLElement) {
|
|
229
|
-
const t = target as HTMLElement;
|
|
230
|
-
|
|
231
|
-
// If a button was clicked, then do not scroll into view, as this will scroll to make the button
|
|
232
|
-
// visible and the click will be ignored - so just return, so that the click works as expected
|
|
233
|
-
if (t.tagName === 'BUTTON') {
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (target instanceof HTMLElement) {
|
|
239
|
-
target?.scrollIntoView({
|
|
240
|
-
behavior: 'smooth',
|
|
241
|
-
block: 'center',
|
|
242
|
-
inline: 'nearest',
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
220
|
</script>
|
|
247
221
|
|
|
248
222
|
<template>
|
|
@@ -383,7 +383,7 @@ export default {
|
|
|
383
383
|
<span class="tab-label"> {{ tab.label }}</span>
|
|
384
384
|
<i
|
|
385
385
|
data-testid="wm-tab-close-button"
|
|
386
|
-
class="closer icon icon-
|
|
386
|
+
class="closer icon icon-x wm-closer-button"
|
|
387
387
|
:alt="t('wm.containerShell.closeShellTab', { tab: tab.label })"
|
|
388
388
|
tabindex="0"
|
|
389
389
|
:aria-label="t('windowmanager.closeTab', { tabId: tab.id })"
|
|
@@ -428,9 +428,9 @@ export default {
|
|
|
428
428
|
</div>
|
|
429
429
|
</div>
|
|
430
430
|
<div
|
|
431
|
-
v-for="
|
|
431
|
+
v-for="tab in tabs"
|
|
432
432
|
:id="`panel-${tab.id}`"
|
|
433
|
-
:key="
|
|
433
|
+
:key="tab.id"
|
|
434
434
|
class="body"
|
|
435
435
|
:class="{'active': tab.id === active}"
|
|
436
436
|
draggable="false"
|
package/composables/resources.ts
CHANGED
|
@@ -21,7 +21,7 @@ export const useResourceIdentifiers = (type: ResourceType) => {
|
|
|
21
21
|
};
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
export const useFetchResourceWithId = async(type: ResourceType, id: IdType) => {
|
|
24
|
+
export const useFetchResourceWithId = async(type: ResourceType, id: IdType, inStore = 'cluster') => {
|
|
25
25
|
const store = useStore();
|
|
26
26
|
const i18n = useI18n(store);
|
|
27
27
|
|
|
@@ -29,7 +29,7 @@ export const useFetchResourceWithId = async(type: ResourceType, id: IdType) => {
|
|
|
29
29
|
const idValue = toValue(id);
|
|
30
30
|
|
|
31
31
|
try {
|
|
32
|
-
return await store.dispatch(
|
|
32
|
+
return await store.dispatch(`${ inStore }/find`, { type: typeValue, id: idValue });
|
|
33
33
|
} catch (ex: any) {
|
|
34
34
|
if (ex.status === 404 || ex.status === 403) {
|
|
35
35
|
store.dispatch('loadingError', new Error(i18n.t('nav.failWhale.resourceIdNotFound', { resource: type, fqid: id }, true)));
|
|
@@ -17,6 +17,8 @@ export const AZURE_MIGRATED = 'auth.cattle.io/azuread-endpoint-migrated';
|
|
|
17
17
|
export const WORKSPACE_ANNOTATION = 'objectset.rio.cattle.io/id';
|
|
18
18
|
export const NODE_ARCHITECTURE = 'kubernetes.io/arch';
|
|
19
19
|
export const IMPORTED_CLUSTER_VERSION_MANAGEMENT = 'rancher.io/imported-cluster-version-management';
|
|
20
|
+
export const UI_PROJECT_SECRET = 'management.cattle.io/project-scoped-secret';
|
|
21
|
+
export const UI_PROJECT_SECRET_COPY = 'management.cattle.io/project-scoped-secret-copy';
|
|
20
22
|
|
|
21
23
|
export const KUBERNETES = {
|
|
22
24
|
SERVICE_ACCOUNT_UID: 'kubernetes.io/service-account.uid',
|
|
@@ -163,6 +165,7 @@ export const HCI = {
|
|
|
163
165
|
NETWORK_TYPE: 'network.harvesterhci.io/type',
|
|
164
166
|
CLUSTER_NETWORK: 'network.harvesterhci.io/clusternetwork',
|
|
165
167
|
PRIMARY_SERVICE: 'cloudprovider.harvesterhci.io/primary-service',
|
|
168
|
+
CPU_MANAGER: 'cpumanager',
|
|
166
169
|
};
|
|
167
170
|
|
|
168
171
|
// Annotations that can be on management.cattle.io.cluster to configure a custom badge
|
|
@@ -192,8 +195,6 @@ export const SYSTEM_LABELS = [
|
|
|
192
195
|
'egress.rke2.io'
|
|
193
196
|
];
|
|
194
197
|
|
|
195
|
-
export const CLOUD_CREDENTIALS = { EXPIRATION: 'rancher.io/expiration-timestamp' };
|
|
196
|
-
|
|
197
198
|
export const OIDC_CLIENT_SECRET_ANNOTATIONS = {
|
|
198
199
|
CREATE: 'cattle.io/oidc-client-secret-create',
|
|
199
200
|
REGEN: 'cattle.io/oidc-client-secret-regenerate',
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { UI_PROJECT_SECRET_COPY } from '@shell/config/labels-annotations';
|
|
1
2
|
import {
|
|
2
3
|
STATE, NAME as NAME_COL, NAMESPACE as NAMESPACE_COL, AGE, OBJECT,
|
|
3
4
|
EVENT_LAST_SEEN_TIME,
|
|
4
|
-
EVENT_TYPE
|
|
5
|
+
EVENT_TYPE,
|
|
6
|
+
SECRET_CLONE
|
|
5
7
|
} from '@shell/config/table-headers';
|
|
6
8
|
|
|
7
9
|
// This file contains table headers
|
|
@@ -78,3 +80,8 @@ export const STEVE_LIST_GROUPS = [{
|
|
|
78
80
|
tooltipKey: 'resourceTable.groupBy.namespace',
|
|
79
81
|
groupLabelKey: 'groupByLabel',
|
|
80
82
|
}];
|
|
83
|
+
|
|
84
|
+
export const STEVE_SECRET_CLONE = {
|
|
85
|
+
...SECRET_CLONE,
|
|
86
|
+
sort: `metadata.annotations[${ UI_PROJECT_SECRET_COPY }]`,
|
|
87
|
+
};
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
HPA_REFERENCE, MIN_REPLICA, MAX_REPLICA, CURRENT_REPLICA,
|
|
22
22
|
ACCESS_KEY, DESCRIPTION, EXPIRES, EXPIRY_STATE, LAST_USED, SUB_TYPE, AGE_NORMAN, SCOPE_NORMAN, PERSISTENT_VOLUME_CLAIM, RECLAIM_POLICY, PV_REASON, WORKLOAD_HEALTH_SCALE, POD_RESTARTS,
|
|
23
23
|
DURATION, MESSAGE, REASON, EVENT_TYPE, OBJECT, ROLE, ROLES, VERSION, INTERNAL_EXTERNAL_IP, KUBE_NODE_OS, CPU, RAM, SECRET_DATA,
|
|
24
|
-
EVENT_LAST_SEEN_TIME
|
|
24
|
+
EVENT_LAST_SEEN_TIME,
|
|
25
25
|
} from '@shell/config/table-headers';
|
|
26
26
|
|
|
27
27
|
import { DSL } from '@shell/store/type-map';
|
|
@@ -94,6 +94,7 @@ export function init(store) {
|
|
|
94
94
|
PVC,
|
|
95
95
|
STORAGE_CLASS,
|
|
96
96
|
SECRET,
|
|
97
|
+
VIRTUAL_TYPES.PROJECT_SECRETS,
|
|
97
98
|
CONFIG_MAP
|
|
98
99
|
], 'storage');
|
|
99
100
|
basicType([
|
|
@@ -187,7 +188,12 @@ export function init(store) {
|
|
|
187
188
|
configureType(NORMAN.CLUSTER_ROLE_TEMPLATE_BINDING, { depaginate: dePaginateNormanBindings });
|
|
188
189
|
configureType(NORMAN.PROJECT_ROLE_TEMPLATE_BINDING, { depaginate: dePaginateNormanBindings });
|
|
189
190
|
configureType(SNAPSHOT, { depaginate: true });
|
|
190
|
-
|
|
191
|
+
|
|
192
|
+
configureType(SECRET, { showListMasthead: false });
|
|
193
|
+
weightType(SECRET, 1, false);
|
|
194
|
+
|
|
195
|
+
configureType(VIRTUAL_TYPES.PROJECT_SECRETS, { showListMasthead: false });
|
|
196
|
+
weightType(VIRTUAL_TYPES.PROJECT_SECRETS, 2, false);
|
|
191
197
|
|
|
192
198
|
configureType(EVENT, { limit: 500 });
|
|
193
199
|
weightType(EVENT, -1, true);
|
|
@@ -624,6 +630,25 @@ export function init(store) {
|
|
|
624
630
|
exact: true,
|
|
625
631
|
});
|
|
626
632
|
|
|
633
|
+
virtualType({
|
|
634
|
+
label: store.getters['i18n/t'](`typeLabel.${ VIRTUAL_TYPES.PROJECT_SECRETS }`, { count: 2 }),
|
|
635
|
+
group: 'storage',
|
|
636
|
+
icon: 'globe',
|
|
637
|
+
namespaced: false,
|
|
638
|
+
ifRancherCluster: true,
|
|
639
|
+
name: VIRTUAL_TYPES.PROJECT_SECRETS,
|
|
640
|
+
weight: -1,
|
|
641
|
+
route: {
|
|
642
|
+
name: 'c-cluster-product-resource',
|
|
643
|
+
params: { resource: VIRTUAL_TYPES.PROJECT_SECRETS }
|
|
644
|
+
},
|
|
645
|
+
exact: true,
|
|
646
|
+
ifHaveType: [{
|
|
647
|
+
store: 'management',
|
|
648
|
+
type: SECRET
|
|
649
|
+
}],
|
|
650
|
+
});
|
|
651
|
+
|
|
627
652
|
// Ignore these types as they are managed through the settings product
|
|
628
653
|
ignoreType(MANAGEMENT.FEATURE);
|
|
629
654
|
ignoreType(MANAGEMENT.SETTING);
|
package/config/query-params.js
CHANGED
|
@@ -80,5 +80,15 @@ export const CLOUD_CREDENTIAL = 'cloud';
|
|
|
80
80
|
export const PROJECT_ID = 'projectId';
|
|
81
81
|
export const FLAT_VIEW = 'flatView';
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Used on the secret create/edit page to determine
|
|
85
|
+
* 1. if the user is creating a normal secret, or a project scoped secret
|
|
86
|
+
* 2. where to return the user on cancel/save
|
|
87
|
+
*/
|
|
88
|
+
export const SECRET_QUERY_PARAMS = {
|
|
89
|
+
NAMESPACED: 'namespaced',
|
|
90
|
+
PROJECT_SCOPED: 'project-scoped'
|
|
91
|
+
};
|
|
92
|
+
export const SECRET_SCOPE = 'scope';
|
|
83
93
|
// RANCHER OIDC CLIENT
|
|
84
94
|
export const RANCHER_AS_OIDC_QUERY_PARAMS = ['scope', 'client_id', 'redirect_uri', 'response_type'];
|
package/config/router/routes.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { NAME as APPS } from '@shell/config/product/apps';
|
|
2
2
|
import { NAME as EXPLORER } from '@shell/config/product/explorer';
|
|
3
3
|
import { NAME as MANAGER } from '@shell/config/product/manager';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
CAPI, MANAGEMENT, BACKUP_RESTORE, COMPLIANCE, VIRTUAL_TYPES
|
|
6
|
+
} from '@shell/config/types';
|
|
5
7
|
import { NAME as AUTH } from '@shell/config/product/auth';
|
|
6
8
|
|
|
7
9
|
// All these imports are related to the install-redirect.js navigation guard.
|
|
@@ -313,6 +315,20 @@ export default [
|
|
|
313
315
|
component: () => interopDefault(import('@shell/pages/c/_cluster/apps/charts/install.vue')),
|
|
314
316
|
name: 'c-cluster-apps-charts-install',
|
|
315
317
|
},
|
|
318
|
+
{
|
|
319
|
+
path: '/c/:cluster/apps/catalog.cattle.io.clusterrepo',
|
|
320
|
+
name: 'c-cluster-apps-catalog-repo',
|
|
321
|
+
redirect(to) {
|
|
322
|
+
return {
|
|
323
|
+
name: 'c-cluster-product-resource',
|
|
324
|
+
params: {
|
|
325
|
+
...to.params,
|
|
326
|
+
product: APPS,
|
|
327
|
+
resource: 'catalog.cattle.io.clusterrepo',
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
},
|
|
331
|
+
},
|
|
316
332
|
]
|
|
317
333
|
},
|
|
318
334
|
{
|
|
@@ -493,6 +509,10 @@ export default [
|
|
|
493
509
|
component: () => interopDefault(import('@shell/pages/c/_cluster/_product/_resource/_id.vue')),
|
|
494
510
|
name: 'c-cluster-product-resource-id',
|
|
495
511
|
meta: { asyncSetup: true }
|
|
512
|
+
}, {
|
|
513
|
+
path: `/c/:cluster/:product/${ VIRTUAL_TYPES.PROJECT_SECRETS }/:namespace/:id`,
|
|
514
|
+
component: () => interopDefault(import(`@shell/pages/c/_cluster/explorer/${ VIRTUAL_TYPES.PROJECT_SECRETS }.vue`)),
|
|
515
|
+
name: `c-cluster-product-${ VIRTUAL_TYPES.PROJECT_SECRETS }-namespace-id`,
|
|
496
516
|
}, {
|
|
497
517
|
path: '/c/:cluster/:product/:resource/:namespace/:id',
|
|
498
518
|
component: () => interopDefault(import('@shell/pages/c/_cluster/_product/_resource/_namespace/_id.vue')),
|
package/config/table-headers.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CATTLE_PUBLIC_ENDPOINTS } from '@shell/config/labels-annotations';
|
|
1
|
+
import { CATTLE_PUBLIC_ENDPOINTS, UI_PROJECT_SECRET_COPY } from '@shell/config/labels-annotations';
|
|
2
2
|
import { NODE as NODE_TYPE } from '@shell/config/types';
|
|
3
3
|
import { COLUMN_BREAKPOINTS } from '@shell/types/store/type-map';
|
|
4
4
|
|
|
@@ -383,6 +383,29 @@ export const SECRET_DATA = {
|
|
|
383
383
|
formatter: 'SecretData'
|
|
384
384
|
};
|
|
385
385
|
|
|
386
|
+
export const SECRET_CLONE = {
|
|
387
|
+
name: 'secret-clone',
|
|
388
|
+
labelKey: 'tableHeaders.secret.project-clone',
|
|
389
|
+
tooltip: 'tableHeaders.secret.project-clone-tooltip',
|
|
390
|
+
value: 'isProjectSecretCopy',
|
|
391
|
+
sort: `metadata.annotations."${ UI_PROJECT_SECRET_COPY }"`,
|
|
392
|
+
search: false,
|
|
393
|
+
formatter: 'Checked',
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
export const SECRET_PROJECT_SCOPED = {
|
|
397
|
+
name: 'secret-project-scoped',
|
|
398
|
+
labelKey: 'tableHeaders.secret.project-scoped',
|
|
399
|
+
tooltip: 'tableHeaders.secret.project-scoped-tooltip',
|
|
400
|
+
value: 'clusterAndProjectLabel',
|
|
401
|
+
// Cannot _sort_ upstream secrets by if they are cluster scoped
|
|
402
|
+
// https://github.com/rancher/rancher/issues/51001
|
|
403
|
+
// metadata.labels[management.cattle.io/project-scoped-secret] - covers both cluster scoped AND clones
|
|
404
|
+
// metadata.annotations[management.cattle.io/project-scoped-secret-copy]
|
|
405
|
+
// sort: [`metadata.labels[${ UI_PROJECT_SECRET }]`, `metadata.annotations[${ UI_PROJECT_SECRET_COPY }]`],
|
|
406
|
+
search: false,
|
|
407
|
+
};
|
|
408
|
+
|
|
386
409
|
export const TARGET_KIND = {
|
|
387
410
|
name: 'target-kind',
|
|
388
411
|
labelKey: 'tableHeaders.targetKind',
|
|
@@ -1145,3 +1168,9 @@ export const UI_PLUGIN_CATALOG = [
|
|
|
1145
1168
|
value: 'repo.metadata.name'
|
|
1146
1169
|
}
|
|
1147
1170
|
];
|
|
1171
|
+
|
|
1172
|
+
// SECRETS
|
|
1173
|
+
export const PROJECT = {
|
|
1174
|
+
name: 'project',
|
|
1175
|
+
labelKey: 'tableHeaders.project',
|
|
1176
|
+
};
|
package/config/types.js
CHANGED
|
@@ -14,7 +14,6 @@ export const STEVE = {
|
|
|
14
14
|
export const NORMAN = {
|
|
15
15
|
APP: 'app',
|
|
16
16
|
AUTH_CONFIG: 'authconfig',
|
|
17
|
-
ETCD_BACKUP: 'etcdbackup',
|
|
18
17
|
CLUSTER: 'cluster',
|
|
19
18
|
CLUSTER_TOKEN: 'clusterregistrationtoken',
|
|
20
19
|
CLUSTER_ROLE_TEMPLATE_BINDING: 'clusterroletemplatebinding',
|
|
@@ -316,6 +315,7 @@ export const VIRTUAL_TYPES = {
|
|
|
316
315
|
CLUSTER_MEMBERS: 'cluster-members',
|
|
317
316
|
PROJECT_NAMESPACES: 'projects-namespaces',
|
|
318
317
|
NAMESPACES: 'namespaces',
|
|
318
|
+
PROJECT_SECRETS: 'projectsecret',
|
|
319
319
|
JWT_AUTHENTICATION: 'jwt.authentication'
|
|
320
320
|
};
|
|
321
321
|
|
package/config/version.js
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import { shallowMount } from '@vue/test-utils';
|
|
2
2
|
import ProvisioningCattleIoCluster from '@shell/detail/provisioning.cattle.io.cluster.vue';
|
|
3
|
+
import * as MastheadComposable from '@shell/components/Resource/Detail/Masthead/composable';
|
|
3
4
|
|
|
4
5
|
jest.mock('@shell/utils/clipboard', () => {
|
|
5
6
|
return { copyTextToClipboard: jest.fn(() => Promise.resolve({})) };
|
|
6
7
|
});
|
|
7
8
|
|
|
9
|
+
jest.mock('@shell/components/Resource/Detail/Masthead/composable');
|
|
10
|
+
|
|
8
11
|
describe('view: provisioning.cattle.io.cluster', () => {
|
|
12
|
+
const useDefaultMastheadPropsSpy = jest.spyOn(MastheadComposable, 'useDefaultMastheadProps');
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
jest.clearAllMocks();
|
|
16
|
+
|
|
17
|
+
useDefaultMastheadPropsSpy.mockReturnValue({} as any);
|
|
18
|
+
});
|
|
19
|
+
|
|
9
20
|
const mockStore = {
|
|
10
21
|
getters: {
|
|
11
22
|
'management/canList': () => true,
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import Workload from '@shell/detail/workload/index.vue';
|
|
2
|
+
|
|
3
|
+
const { findMatchingIngresses } = Workload.methods;
|
|
4
|
+
|
|
5
|
+
describe('findMatchingIngresses', () => {
|
|
6
|
+
it('should do nothing if ingress schema is not present', () => {
|
|
7
|
+
const mockThis = {
|
|
8
|
+
ingressSchema: undefined,
|
|
9
|
+
matchingIngresses: [],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
findMatchingIngresses.call(mockThis);
|
|
13
|
+
expect(mockThis.matchingIngresses).toStrictEqual([]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should not find any ingresses if there are none', () => {
|
|
17
|
+
const mockThis = {
|
|
18
|
+
ingressSchema: true,
|
|
19
|
+
allIngresses: [],
|
|
20
|
+
matchingServices: [],
|
|
21
|
+
matchingIngresses: [],
|
|
22
|
+
value: { metadata: { namespace: 'test' } }
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
findMatchingIngresses.call(mockThis);
|
|
26
|
+
expect(mockThis.matchingIngresses).toStrictEqual([]);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should find matching ingresses', () => {
|
|
30
|
+
const mockThis = {
|
|
31
|
+
ingressSchema: true,
|
|
32
|
+
allIngresses: [
|
|
33
|
+
{ // matching
|
|
34
|
+
metadata: { namespace: 'test' },
|
|
35
|
+
spec: { rules: [{ http: { paths: [{ backend: { service: { name: 'service1' } } }] } }] }
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
39
|
+
matchingIngresses: [],
|
|
40
|
+
value: { metadata: { namespace: 'test' } }
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
findMatchingIngresses.call(mockThis);
|
|
44
|
+
expect(mockThis.matchingIngresses).toHaveLength(1);
|
|
45
|
+
expect(mockThis.matchingIngresses[0]).toStrictEqual(mockThis.allIngresses[0]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should not match ingresses from other namespaces', () => {
|
|
49
|
+
const mockThis = {
|
|
50
|
+
ingressSchema: true,
|
|
51
|
+
allIngresses: [
|
|
52
|
+
{ // not matching
|
|
53
|
+
metadata: { namespace: 'other' },
|
|
54
|
+
spec: { rules: [{ http: { paths: [{ backend: { service: { name: 'service1' } } }] } }] }
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
58
|
+
matchingIngresses: [],
|
|
59
|
+
value: { metadata: { namespace: 'test' } }
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
findMatchingIngresses.call(mockThis);
|
|
63
|
+
expect(mockThis.matchingIngresses).toHaveLength(0);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should not match ingresses pointing to other services', () => {
|
|
67
|
+
const mockThis = {
|
|
68
|
+
ingressSchema: true,
|
|
69
|
+
allIngresses: [
|
|
70
|
+
{ // not matching
|
|
71
|
+
metadata: { namespace: 'test' },
|
|
72
|
+
spec: { rules: [{ http: { paths: [{ backend: { service: { name: 'service2' } } }] } }] }
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
76
|
+
matchingIngresses: [],
|
|
77
|
+
value: { metadata: { namespace: 'test' } }
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
findMatchingIngresses.call(mockThis);
|
|
81
|
+
expect(mockThis.matchingIngresses).toHaveLength(0);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should handle ingresses with no rules', () => {
|
|
85
|
+
const mockThis = {
|
|
86
|
+
ingressSchema: true,
|
|
87
|
+
allIngresses: [
|
|
88
|
+
{
|
|
89
|
+
metadata: { namespace: 'test' },
|
|
90
|
+
spec: { }
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
94
|
+
matchingIngresses: [],
|
|
95
|
+
value: { metadata: { namespace: 'test' } }
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
findMatchingIngresses.call(mockThis);
|
|
99
|
+
expect(mockThis.matchingIngresses).toHaveLength(0);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should handle ingress rules with no paths', () => {
|
|
103
|
+
const mockThis = {
|
|
104
|
+
ingressSchema: true,
|
|
105
|
+
allIngresses: [
|
|
106
|
+
{
|
|
107
|
+
metadata: { namespace: 'test' },
|
|
108
|
+
spec: { rules: [{ http: {} }] }
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
112
|
+
matchingIngresses: [],
|
|
113
|
+
value: { metadata: { namespace: 'test' } }
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
findMatchingIngresses.call(mockThis);
|
|
117
|
+
expect(mockThis.matchingIngresses).toHaveLength(0);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should handle ingress paths with no backend service', () => {
|
|
121
|
+
const mockThis = {
|
|
122
|
+
ingressSchema: true,
|
|
123
|
+
allIngresses: [
|
|
124
|
+
{
|
|
125
|
+
metadata: { namespace: 'test' },
|
|
126
|
+
spec: { rules: [{ http: { paths: [{ backend: {} }] } }] }
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
130
|
+
matchingIngresses: [],
|
|
131
|
+
value: { metadata: { namespace: 'test' } }
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
findMatchingIngresses.call(mockThis);
|
|
135
|
+
expect(mockThis.matchingIngresses).toHaveLength(0);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should find one of many ingresses', () => {
|
|
139
|
+
const mockThis = {
|
|
140
|
+
ingressSchema: true,
|
|
141
|
+
allIngresses: [
|
|
142
|
+
{ // not matching
|
|
143
|
+
metadata: { namespace: 'other' },
|
|
144
|
+
spec: { rules: [{ http: { paths: [{ backend: { service: { name: 'service1' } } }] } }] }
|
|
145
|
+
},
|
|
146
|
+
{ // matching
|
|
147
|
+
metadata: { namespace: 'test' },
|
|
148
|
+
spec: { rules: [{ http: { paths: [{ backend: { service: { name: 'service1' } } }] } }] }
|
|
149
|
+
},
|
|
150
|
+
{ // not matching
|
|
151
|
+
metadata: { namespace: 'test' },
|
|
152
|
+
spec: { rules: [{ http: { paths: [{ backend: { service: { name: 'service2' } } }] } }] }
|
|
153
|
+
}
|
|
154
|
+
],
|
|
155
|
+
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
156
|
+
matchingIngresses: [],
|
|
157
|
+
value: { metadata: { namespace: 'test' } }
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
findMatchingIngresses.call(mockThis);
|
|
161
|
+
expect(mockThis.matchingIngresses).toHaveLength(1);
|
|
162
|
+
expect(mockThis.matchingIngresses[0]).toStrictEqual(mockThis.allIngresses[1]);
|
|
163
|
+
});
|
|
164
|
+
});
|