@rancher/shell 3.0.5-rc.7 → 3.0.5-rc.9
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 +19 -0
- package/assets/styles/base/_helpers.scss +10 -0
- package/assets/styles/base/_variables.scss +1 -1
- package/assets/styles/fonts/_icons.scss +1 -32
- package/assets/styles/global/_layout.scss +1 -1
- package/assets/styles/global/_tooltip.scss +7 -4
- package/assets/styles/themes/_dark.scss +272 -259
- package/assets/styles/themes/_light.scss +551 -516
- package/assets/styles/themes/_modern.scss +936 -0
- package/assets/translations/en-us.yaml +219 -38
- package/assets/translations/zh-hans.yaml +0 -1
- package/chart/__tests__/S3.test.ts +2 -1
- package/chart/monitoring/grafana/index.vue +8 -2
- package/cloud-credential/generic.vue +18 -10
- package/cloud-credential/harvester.vue +1 -9
- package/components/ActionMenuShell.vue +3 -1
- package/components/AdvancedSection.vue +8 -0
- package/components/ChartReadme.vue +17 -7
- package/components/Cron/CronExpressionEditor.vue +299 -0
- package/components/Cron/CronExpressionEditorModal.vue +247 -0
- package/components/Cron/CronTooltip.vue +87 -0
- package/components/Cron/types.ts +13 -0
- package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +1 -26
- package/components/Drawer/ResourceDetailDrawer/composables.ts +0 -23
- package/components/Drawer/ResourceDetailDrawer/index.vue +17 -4
- package/components/ForceDirectedTreeChart/composable.ts +11 -0
- package/components/InstallHelmCharts.vue +656 -0
- package/components/LazyImage.vue +60 -4
- package/components/LocaleSelector.vue +7 -2
- package/components/Markdown.vue +4 -0
- package/components/PromptModal.vue +1 -1
- package/components/Resource/Detail/Card/__tests__/StateCard.test.ts +1 -0
- package/components/Resource/Detail/CopyToClipboard.vue +78 -0
- package/components/Resource/Detail/FetchLoader/__tests__/composables.test.ts +69 -0
- package/components/Resource/Detail/FetchLoader/composables.ts +27 -0
- package/components/Resource/Detail/Masthead/composable.ts +16 -0
- package/components/Resource/Detail/Masthead/index.vue +37 -0
- package/components/Resource/Detail/Metadata/Annotations/__tests__/index.test.ts +1 -1
- package/components/Resource/Detail/Metadata/Annotations/index.vue +1 -1
- package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +13 -61
- package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/index.test.ts +33 -6
- package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +29 -43
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +25 -5
- package/components/Resource/Detail/Metadata/KeyValue.vue +12 -23
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +144 -0
- package/components/Resource/Detail/Metadata/Labels/__tests__/index.test.ts +1 -0
- package/components/Resource/Detail/Metadata/Labels/index.vue +1 -0
- package/components/Resource/Detail/Metadata/__tests__/KeyValue.test.ts +30 -32
- package/components/Resource/Detail/Metadata/__tests__/KeyValueRow.test.ts +108 -0
- package/components/Resource/Detail/Metadata/__tests__/composables.test.ts +10 -20
- package/components/Resource/Detail/Metadata/__tests__/index.test.ts +12 -5
- package/components/Resource/Detail/Metadata/composables.ts +9 -10
- package/components/Resource/Detail/Metadata/index.vue +18 -2
- package/components/Resource/Detail/Page.vue +35 -21
- package/components/Resource/Detail/Preview/Content.vue +63 -0
- package/components/Resource/Detail/Preview/Preview.vue +128 -0
- package/components/Resource/Detail/Preview/__tests__/Content.spec.ts +71 -0
- package/components/Resource/Detail/Preview/__tests__/Preview.spec.ts +121 -0
- package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +141 -0
- package/components/Resource/Detail/ResourcePopover/__tests__/ResourcePopoverCard.test.ts +136 -0
- package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +245 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +226 -0
- package/components/Resource/Detail/SpacedRow.vue +1 -0
- package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +8 -14
- package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +1 -1
- package/components/Resource/Detail/TitleBar/composables.ts +3 -6
- package/components/Resource/Detail/TitleBar/index.vue +11 -29
- package/components/Resource/Detail/ViewOptions/composable.ts +9 -0
- package/components/Resource/Detail/ViewOptions/index.vue +41 -0
- package/components/Resource/Detail/__tests__/CopyToClipboard.spec.ts +82 -0
- package/components/ResourceDetail/Masthead/legacy.vue +0 -19
- package/components/ResourceDetail/index.vue +544 -74
- package/components/ResourceTable.vue +24 -0
- package/components/SlideInPanelManager.vue +10 -3
- package/components/SortableTable/index.vue +11 -5
- package/components/SortableTable/paging.js +3 -0
- package/components/Tabbed/Tab.vue +43 -1
- package/components/Tabbed/index.vue +32 -4
- package/components/__tests__/Cron/CronExpressionEditor.test.ts +151 -0
- package/components/__tests__/Cron/CronExpressionEditorModal.test.ts +81 -0
- package/components/__tests__/LazyImage.spec.ts +121 -0
- package/components/auth/login/saml.vue +86 -0
- package/components/fleet/FleetStatus.vue +4 -0
- package/components/form/ClusterAppearance.vue +5 -0
- package/components/form/LabeledSelect.vue +8 -8
- package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
- package/components/form/ProjectMemberEditor.vue +1 -1
- package/components/form/ResourceLabeledSelect.vue +19 -6
- package/components/form/ResourceTabs/composable.ts +54 -0
- package/components/form/ResourceTabs/index.vue +30 -7
- package/components/form/SecretSelector.vue +9 -0
- package/components/form/Select.vue +13 -10
- package/components/form/__tests__/LabeledSelect.test.ts +133 -0
- package/components/form/__tests__/Select.test.ts +134 -0
- package/components/form/labeled-select-utils/labeled-select-pagination.ts +3 -38
- package/components/formatter/FleetApplicationSource.vue +25 -17
- package/components/nav/Favorite.vue +4 -0
- package/components/nav/NotificationCenter/Notification.vue +1 -27
- package/components/nav/WindowManager/index.vue +3 -3
- package/composables/useExtensionManager.ts +17 -0
- package/config/home-links.js +12 -0
- package/config/labels-annotations.js +1 -3
- package/config/page-actions.js +0 -1
- package/config/product/explorer.js +3 -1
- package/config/product/fleet.js +2 -7
- package/config/product/manager.js +0 -5
- package/config/query-params.js +1 -0
- package/config/router/navigation-guards/clusters.js +2 -1
- package/config/router/navigation-guards/products.js +1 -1
- package/core/extension-manager-impl.js +518 -0
- package/core/plugins.js +35 -468
- package/core/types.ts +8 -2
- package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +1 -0
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +11 -0
- package/detail/__tests__/workload.test.ts +164 -0
- package/detail/catalog.cattle.io.app.vue +7 -4
- package/detail/configmap.vue +33 -75
- package/detail/fleet.cattle.io.bundle.vue +1 -5
- package/detail/fleet.cattle.io.cluster.vue +3 -2
- package/detail/fleet.cattle.io.gitrepo.vue +76 -49
- package/detail/fleet.cattle.io.helmop.vue +78 -49
- package/detail/projectsecret.vue +11 -0
- package/detail/provisioning.cattle.io.cluster.vue +350 -324
- package/detail/secret.vue +49 -308
- package/detail/workload/index.vue +38 -21
- package/dialog/AddonConfigConfirmationDialog.vue +1 -1
- package/dialog/GenericPrompt.vue +1 -1
- package/dialog/ImportDialog.vue +9 -2
- package/dialog/InstallExtensionDialog.vue +26 -15
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -1
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +224 -0
- package/edit/__tests__/resources.cattle.io.restore.test.ts +106 -0
- package/edit/cloudcredential.vue +31 -17
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +10 -2
- package/edit/fleet.cattle.io.cluster.vue +19 -0
- package/edit/fleet.cattle.io.gitrepo.vue +28 -22
- 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/monitoring.coreos.com.alertmanagerconfig/index.vue +12 -11
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +11 -1
- package/edit/networking.k8s.io.ingress/Certificate.vue +9 -11
- 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.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/index.vue +14 -19
- package/edit/provisioning.cattle.io.cluster/rke2.vue +31 -15
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +9 -7
- 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 +30 -31
- 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/resources.cattle.io.restore.vue +5 -8
- package/edit/workload/index.vue +5 -14
- package/list/__tests__/workload.test.ts +1 -0
- package/list/provisioning.cattle.io.cluster.vue +1 -69
- package/list/workload.vue +8 -1
- package/machine-config/__tests__/vmwarevsphere.test.ts +5 -7
- package/machine-config/components/GCEImage.vue +6 -5
- package/machine-config/google.vue +20 -7
- package/machine-config/vmwarevsphere.vue +7 -17
- package/mixins/__tests__/chart.test.ts +139 -1
- package/mixins/chart.js +58 -20
- package/mixins/resource-fetch-api-pagination.js +3 -4
- package/models/__tests__/chart.test.ts +111 -80
- package/models/__tests__/fleet.cattle.io.helmop.test.ts +224 -0
- package/models/__tests__/namespace.test.ts +69 -0
- package/models/__tests__/node.test.ts +7 -63
- package/models/apps.statefulset.js +8 -10
- package/models/catalog.cattle.io.app.js +1 -1
- package/models/catalog.cattle.io.operation.js +1 -1
- package/models/chart.js +41 -21
- 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/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 +16 -63
- package/models/fleet.cattle.io.bundle.js +1 -38
- package/models/fleet.cattle.io.gitrepo.js +19 -1
- package/models/fleet.cattle.io.helmop.js +30 -22
- package/models/management.cattle.io.project.js +12 -0
- package/models/management.cattle.io.setting.js +4 -0
- package/models/namespace.js +30 -0
- package/models/persistentvolumeclaim.js +1 -1
- package/models/pod.js +2 -2
- package/models/provisioning.cattle.io.cluster.js +16 -40
- package/models/rke.cattle.io.etcdsnapshot.js +1 -1
- package/models/secret.js +4 -0
- package/models/storage.k8s.io.storageclass.js +2 -2
- package/models/workload.js +6 -3
- package/package.json +19 -18
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +26 -10
- 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 +440 -183
- package/pages/c/_cluster/apps/charts/index.vue +1 -0
- package/pages/c/_cluster/apps/charts/install.vue +7 -6
- package/pages/c/_cluster/explorer/projectsecret.vue +3 -13
- package/pages/c/_cluster/explorer/tools/__tests__/index.test.ts +102 -12
- package/pages/c/_cluster/explorer/tools/index.vue +145 -254
- package/pages/c/_cluster/fleet/__tests__/index.test.ts +608 -314
- package/pages/c/_cluster/fleet/index.vue +103 -44
- package/pages/c/_cluster/manager/cloudCredential/index.vue +20 -60
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +12 -2
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +11 -4
- package/pages/c/_cluster/uiplugins/__tests__/index.spec.ts +318 -0
- package/pages/c/_cluster/uiplugins/index.vue +256 -387
- package/pages/home.vue +1 -9
- package/plugins/dashboard-store/actions.js +42 -22
- package/plugins/dashboard-store/resource-class.js +80 -0
- 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/subscribe.js +192 -19
- package/plugins/steve/worker/web-worker.advanced.js +2 -0
- package/public/index.html +2 -1
- package/rancher-components/Card/Card.vue +1 -19
- package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
- package/rancher-components/Form/Radio/RadioButton.vue +1 -1
- package/rancher-components/Form/Radio/RadioGroup.vue +1 -1
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -11
- package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.test.ts +53 -0
- package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.vue +65 -0
- package/rancher-components/Pill/RcCounterBadge/index.ts +1 -0
- package/rancher-components/Pill/RcCounterBadge/types.ts +7 -0
- 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/RcTag/RcTag.test.ts +64 -0
- package/rancher-components/Pill/RcTag/RcTag.vue +94 -0
- package/rancher-components/Pill/RcTag/index.ts +1 -0
- package/rancher-components/Pill/RcTag/types.ts +9 -0
- package/rancher-components/Pill/types.ts +3 -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 +41 -6
- package/rancher-components/RcItemCard/RcItemCardAction.vue +12 -0
- package/store/__tests__/catalog.test.ts +156 -1
- package/store/aws.js +19 -8
- package/store/catalog.js +10 -5
- package/store/type-map.js +3 -15
- package/types/extension-manager.ts +26 -0
- package/types/resources/settings.d.ts +1 -1
- package/types/shell/index.d.ts +149 -44
- package/types/uiplugins.ts +73 -0
- package/utils/__tests__/back-off.test.ts +354 -0
- package/utils/__tests__/kontainer.test.ts +19 -0
- package/utils/__tests__/product.test.ts +129 -0
- package/utils/__tests__/resource.test.ts +87 -0
- package/utils/__tests__/uiplugins.test.ts +84 -0
- package/utils/alertmanagerconfig.js +2 -2
- package/utils/auth.js +3 -76
- package/utils/back-off.ts +176 -0
- package/utils/dynamic-importer.js +8 -0
- package/utils/kontainer.ts +3 -5
- package/utils/product.ts +39 -0
- package/utils/resource.ts +35 -0
- package/utils/select.js +0 -24
- 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 +91 -7
- package/utils/validators/formRules/index.ts +84 -8
- package/utils/validators/setting.js +17 -0
- package/vue.config.js +1 -1
- package/cloud-credential/__tests__/harvester.test.ts +0 -18
- package/components/Resource/Detail/Metadata/Rectangle.vue +0 -34
- package/components/Resource/Detail/Metadata/__tests__/Rectangle.test.ts +0 -24
- package/components/ResourceDetail/Masthead/__tests__/legacy.test.ts +0 -65
- package/components/ResourceDetail/__tests__/index.test.ts +0 -135
- package/components/ResourceDetail/legacy.vue +0 -562
- package/components/formatter/CloudCredExpired.vue +0 -69
- package/pages/explorer/resource/detail/configmap.vue +0 -42
- package/pages/explorer/resource/detail/projectsecret.vue +0 -9
- package/pages/explorer/resource/detail/secret.vue +0 -63
- package/utils/aws.js +0 -0
- /package/components/{ForceDirectedTreeChart.vue → ForceDirectedTreeChart/index.vue} +0 -0
package/pages/home.vue
CHANGED
|
@@ -22,7 +22,7 @@ import { filterHiddenLocalCluster, filterOnlyKubernetesClusters, paginationFilte
|
|
|
22
22
|
import TabTitle from '@shell/components/TabTitle.vue';
|
|
23
23
|
import { ActionFindPageArgs } from '@shell/types/store/dashboard-store.types';
|
|
24
24
|
|
|
25
|
-
import {
|
|
25
|
+
import { SET_LOGIN_ACTION, SHOW_HIDE_BANNER_ACTION } from '@shell/config/page-actions';
|
|
26
26
|
import { STEVE_NAME_COL, STEVE_STATE_COL } from '@shell/config/pagination-table-headers';
|
|
27
27
|
import { PaginationParamFilter, FilterArgs, PaginationFilterField, PaginationArgs } from '@shell/types/store/pagination.types';
|
|
28
28
|
import ProvCluster from '@shell/models/provisioning.cattle.io.cluster';
|
|
@@ -75,10 +75,6 @@ export default defineComponent({
|
|
|
75
75
|
label: this.t('nav.header.showHideBanner'),
|
|
76
76
|
action: SHOW_HIDE_BANNER_ACTION
|
|
77
77
|
},
|
|
78
|
-
{
|
|
79
|
-
label: this.t('nav.header.restoreCards'),
|
|
80
|
-
action: RESET_CARDS_ACTION
|
|
81
|
-
},
|
|
82
78
|
],
|
|
83
79
|
vendor: getVendor(),
|
|
84
80
|
|
|
@@ -368,10 +364,6 @@ export default defineComponent({
|
|
|
368
364
|
*/
|
|
369
365
|
handlePageAction(action: any) {
|
|
370
366
|
switch (action.action) {
|
|
371
|
-
case RESET_CARDS_ACTION:
|
|
372
|
-
this.resetCards();
|
|
373
|
-
break;
|
|
374
|
-
|
|
375
367
|
case SHOW_HIDE_BANNER_ACTION:
|
|
376
368
|
this.toggleBanner();
|
|
377
369
|
break;
|
|
@@ -79,6 +79,29 @@ const findAllGetter = (getters, type, opt) => {
|
|
|
79
79
|
return opt.namespaced ? getters.matching(type, null, opt.namespaced, { skipSelector: true }) : getters.all(type);
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
+
const createFindWatchArg = ({
|
|
83
|
+
type, id, opt, res
|
|
84
|
+
}) => {
|
|
85
|
+
const revision = typeof opt.revision !== 'undefined' ? opt.revision : res?.metadata?.resourceVersion;
|
|
86
|
+
const watchMsg = {
|
|
87
|
+
type,
|
|
88
|
+
id,
|
|
89
|
+
// Although not used by sockets, we need this for when resyncWatch calls find... which needs namespace to construct the url
|
|
90
|
+
namespace: opt.namespaced,
|
|
91
|
+
revision: revision || '',
|
|
92
|
+
force: opt.forceWatch === true,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const idx = id.indexOf('/');
|
|
96
|
+
|
|
97
|
+
if ( idx > 0 ) {
|
|
98
|
+
watchMsg.namespace = id.substr(0, idx);
|
|
99
|
+
watchMsg.id = id.substr(idx + 1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return watchMsg;
|
|
103
|
+
};
|
|
104
|
+
|
|
82
105
|
export default {
|
|
83
106
|
request() {
|
|
84
107
|
throw new Error('Not Implemented');
|
|
@@ -657,6 +680,12 @@ export default {
|
|
|
657
680
|
out = getters.byId(type, id);
|
|
658
681
|
|
|
659
682
|
if ( out ) {
|
|
683
|
+
if ( opt.watch !== false ) {
|
|
684
|
+
dispatch('watch', createFindWatchArg({
|
|
685
|
+
type, id, opt, res: undefined
|
|
686
|
+
}));
|
|
687
|
+
}
|
|
688
|
+
|
|
660
689
|
return out;
|
|
661
690
|
}
|
|
662
691
|
}
|
|
@@ -669,26 +698,9 @@ export default {
|
|
|
669
698
|
await dispatch('load', { data: res });
|
|
670
699
|
|
|
671
700
|
if ( opt.watch !== false ) {
|
|
672
|
-
|
|
673
|
-
type,
|
|
674
|
-
|
|
675
|
-
// Although not used by sockets, we need this for when resyncWatch calls find... which needs namespace to construct the url
|
|
676
|
-
namespace: opt.namespaced,
|
|
677
|
-
// Override the revision. Used in cases where we need to avoid using the resource's own revision which would be `too old`.
|
|
678
|
-
// For the above case opt.revision will be `null`. If left as `undefined` the subscribe mechanism will try to determine a revision
|
|
679
|
-
// from resources in store (which would be this one, with the too old revision)
|
|
680
|
-
revision: typeof opt.revision !== 'undefined' ? opt.revision : res?.metadata?.resourceVersion,
|
|
681
|
-
force: opt.forceWatch === true,
|
|
682
|
-
};
|
|
683
|
-
|
|
684
|
-
const idx = id.indexOf('/');
|
|
685
|
-
|
|
686
|
-
if ( idx > 0 ) {
|
|
687
|
-
watchMsg.namespace = id.substr(0, idx);
|
|
688
|
-
watchMsg.id = id.substr(idx + 1);
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
dispatch('watch', watchMsg);
|
|
701
|
+
dispatch('watch', createFindWatchArg({
|
|
702
|
+
type, id, opt, res
|
|
703
|
+
}));
|
|
692
704
|
}
|
|
693
705
|
|
|
694
706
|
out = getters.byId(type, id);
|
|
@@ -808,13 +820,21 @@ export default {
|
|
|
808
820
|
return classify(ctx, resource.toJSON(), true);
|
|
809
821
|
},
|
|
810
822
|
|
|
811
|
-
|
|
812
|
-
|
|
823
|
+
/**
|
|
824
|
+
* Remove all cached entries for a resource and stop watches
|
|
825
|
+
*/
|
|
813
826
|
forgetType({ commit, dispatch, state }, type, compareWatches) {
|
|
827
|
+
// Stop all known watches
|
|
814
828
|
state.started
|
|
815
829
|
.filter((entry) => compareWatches ? compareWatches(entry) : entry.type === type)
|
|
816
830
|
.forEach((entry) => dispatch('unwatch', entry));
|
|
817
831
|
|
|
832
|
+
// Stop all known back-off watch processes for this type
|
|
833
|
+
dispatch('resetWatchBackOff', {
|
|
834
|
+
type, compareWatches, resetStarted: false
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
// Remove entries from store
|
|
818
838
|
commit('forgetType', type);
|
|
819
839
|
},
|
|
820
840
|
|
|
@@ -36,6 +36,7 @@ import { handleConflict } from '@shell/plugins/dashboard-store/normalize';
|
|
|
36
36
|
import { ExtensionPoint, ActionLocation } from '@shell/core/types';
|
|
37
37
|
import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
|
|
38
38
|
import { parse } from '@shell/utils/selector';
|
|
39
|
+
import { importDrawer } from '@shell/utils/dynamic-importer';
|
|
39
40
|
|
|
40
41
|
export const DNS_LIKE_TYPES = ['dnsLabel', 'dnsLabelRestricted', 'hostname'];
|
|
41
42
|
|
|
@@ -859,6 +860,10 @@ export default class Resource {
|
|
|
859
860
|
|
|
860
861
|
// ------------------------------------------------------------------
|
|
861
862
|
|
|
863
|
+
get canEdit() {
|
|
864
|
+
return this.canUpdate && this.canCustomEdit;
|
|
865
|
+
}
|
|
866
|
+
|
|
862
867
|
get availableActions() {
|
|
863
868
|
const all = this._availableActions;
|
|
864
869
|
|
|
@@ -898,6 +903,26 @@ export default class Resource {
|
|
|
898
903
|
return out;
|
|
899
904
|
}
|
|
900
905
|
|
|
906
|
+
showConfiguration(returnFocusSelector) {
|
|
907
|
+
const onClose = () => this.$ctx.commit('slideInPanel/close', undefined, { root: true });
|
|
908
|
+
|
|
909
|
+
this.$ctx.commit('slideInPanel/open', {
|
|
910
|
+
component: importDrawer('ResourceDetailDrawer'),
|
|
911
|
+
componentProps: {
|
|
912
|
+
resource: this,
|
|
913
|
+
onClose,
|
|
914
|
+
width: '73%',
|
|
915
|
+
// We want this to be full viewport height top to bottom
|
|
916
|
+
height: '100vh',
|
|
917
|
+
top: '0',
|
|
918
|
+
'z-index': 101, // We want this to be above the main side menu
|
|
919
|
+
closeOnRouteChange: ['name', 'params', 'query'], // We want to ignore hash changes, tables in extensions can trigger the drawer to close while opening
|
|
920
|
+
triggerFocusTrap: true,
|
|
921
|
+
returnFocusSelector
|
|
922
|
+
}
|
|
923
|
+
}, { root: true });
|
|
924
|
+
}
|
|
925
|
+
|
|
901
926
|
// You can add custom actions by overriding your own availableActions (and probably reading super._availableActions)
|
|
902
927
|
get _availableActions() {
|
|
903
928
|
// get menu actions available by plugins configuration
|
|
@@ -905,6 +930,12 @@ export default class Resource {
|
|
|
905
930
|
const extensionMenuActions = getApplicableExtensionEnhancements(this.$rootState, ExtensionPoint.ACTION, ActionLocation.TABLE, currentRoute, this);
|
|
906
931
|
|
|
907
932
|
const all = [
|
|
933
|
+
{
|
|
934
|
+
action: 'showConfiguration',
|
|
935
|
+
label: this.t('action.showConfiguration'),
|
|
936
|
+
icon: 'icon icon-document',
|
|
937
|
+
enabled: this.disableResourceDetailDrawer !== true && (this.canCustomEdit || this.canYaml), // If the resource can't show an edit or a yaml we don't want to show the configuration drawer
|
|
938
|
+
},
|
|
908
939
|
{ divider: true },
|
|
909
940
|
{
|
|
910
941
|
action: this.canUpdate ? 'goToEdit' : 'goToViewConfig',
|
|
@@ -1816,6 +1847,55 @@ export default class Resource {
|
|
|
1816
1847
|
return details;
|
|
1817
1848
|
}
|
|
1818
1849
|
|
|
1850
|
+
get glance() {
|
|
1851
|
+
return this._glance;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
get _glance() {
|
|
1855
|
+
const type = this.parentNameOverride || this.$rootGetters['type-map/labelFor'](this.schema);
|
|
1856
|
+
|
|
1857
|
+
return [
|
|
1858
|
+
{
|
|
1859
|
+
name: 'state',
|
|
1860
|
+
label: this.t('component.resource.detail.glance.state'),
|
|
1861
|
+
formatter: 'BadgeStateFormatter',
|
|
1862
|
+
formatterOpts: { row: this },
|
|
1863
|
+
content: this.stateDisplay
|
|
1864
|
+
},
|
|
1865
|
+
{
|
|
1866
|
+
name: 'type',
|
|
1867
|
+
label: this.t('component.resource.detail.glance.type'),
|
|
1868
|
+
formatter: 'Link',
|
|
1869
|
+
formatterOpts: {
|
|
1870
|
+
to: this.listLocation, row: {}, options: { internal: true }
|
|
1871
|
+
},
|
|
1872
|
+
content: type
|
|
1873
|
+
},
|
|
1874
|
+
{
|
|
1875
|
+
name: 'namespace',
|
|
1876
|
+
label: this.t('component.resource.detail.glance.namespace'),
|
|
1877
|
+
formatter: 'Link',
|
|
1878
|
+
formatterOpts: {
|
|
1879
|
+
to: {
|
|
1880
|
+
name: `c-cluster-product-resource-id`,
|
|
1881
|
+
product: this.$rootGetters['currentProduct'].id,
|
|
1882
|
+
cluster: this.$rootGetters['currentCluster'].id,
|
|
1883
|
+
resource: this.type
|
|
1884
|
+
},
|
|
1885
|
+
row: {},
|
|
1886
|
+
options: { internal: true }
|
|
1887
|
+
},
|
|
1888
|
+
content: this.namespacedName
|
|
1889
|
+
},
|
|
1890
|
+
{
|
|
1891
|
+
name: 'age',
|
|
1892
|
+
label: this.t('component.resource.detail.glance.age'),
|
|
1893
|
+
formatter: 'LiveDate',
|
|
1894
|
+
content: this.creationTimestamp
|
|
1895
|
+
}
|
|
1896
|
+
];
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1819
1899
|
get t() {
|
|
1820
1900
|
return this.$rootGetters['i18n/t'];
|
|
1821
1901
|
}
|
|
@@ -120,7 +120,7 @@ describe('steve: getters:', () => {
|
|
|
120
120
|
expect(urlOptionsGetter('/v1/foo', { excludeFields: ['bar'] })).toBe('/v1/foo?exclude=bar');
|
|
121
121
|
});
|
|
122
122
|
it('returns a string without an exclude statement for "managedFields" if omitExcludeFields includes it and the url starts with "/v1/"', () => {
|
|
123
|
-
expect(urlOptionsGetter('/v1/foo', { omitExcludeFields: ['metadata.managedFields'] })).toBe('/v1/foo
|
|
123
|
+
expect(urlOptionsGetter('/v1/foo', { omitExcludeFields: ['metadata.managedFields'] })).toBe('/v1/foo');
|
|
124
124
|
});
|
|
125
125
|
it('returns a string without an exclude statement if excludeFields is set but the url does not start with "/v1/"', () => {
|
|
126
126
|
expect(urlOptionsGetter('foo', { excludeFields: ['bar'] })).toBe('foo');
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { actions, getters } from '../subscribe';
|
|
1
|
+
import { actions, getters, mutations } from '../subscribe';
|
|
2
|
+
import { REVISION_TOO_OLD } from '../../../utils/socket';
|
|
3
|
+
import { STEVE_WATCH_EVENT } from '../../../types/store/subscribe.types';
|
|
4
|
+
import backOff from '../../../utils/back-off';
|
|
2
5
|
|
|
3
6
|
describe('steve: subscribe', () => {
|
|
4
7
|
describe('actions', () => {
|
|
@@ -171,4 +174,259 @@ describe('steve: subscribe', () => {
|
|
|
171
174
|
});
|
|
172
175
|
});
|
|
173
176
|
});
|
|
177
|
+
|
|
178
|
+
describe('backoff', () => {
|
|
179
|
+
const waitForBackOff = async(advanceTimersByTime = 20000) => {
|
|
180
|
+
jest.advanceTimersByTime(advanceTimersByTime);
|
|
181
|
+
// jest.advanceTimersByTime(advanceTimersByTime);
|
|
182
|
+
await Promise.resolve();
|
|
183
|
+
await Promise.resolve();
|
|
184
|
+
await Promise.resolve();
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
describe('stale cache in replicate that handles watch', () => {
|
|
188
|
+
/**
|
|
189
|
+
1. ui makes http request.
|
|
190
|
+
- it's handled by up-to-date replica A
|
|
191
|
+
- response contains an up-to-date revision X
|
|
192
|
+
2. ui makes watch request referencing up-to-date revision X from A
|
|
193
|
+
- it's received by replica B with a stale cache which does not contain revision X.
|
|
194
|
+
- replicate B rejects watch with unknown revision message (i.e. 'too old')
|
|
195
|
+
3. ui receives unknown revision and makes a new request
|
|
196
|
+
- this should backoff until eventually succeeding
|
|
197
|
+
*/
|
|
198
|
+
|
|
199
|
+
const startWatch = ({
|
|
200
|
+
ctx,
|
|
201
|
+
obj, msg,
|
|
202
|
+
revision
|
|
203
|
+
}) => {
|
|
204
|
+
const {
|
|
205
|
+
state, dispatch, getters, rootGetters, commit
|
|
206
|
+
} = ctx;
|
|
207
|
+
|
|
208
|
+
// call watch
|
|
209
|
+
actions.watch({
|
|
210
|
+
state, dispatch, getters, rootGetters
|
|
211
|
+
}, {
|
|
212
|
+
...obj,
|
|
213
|
+
revision,
|
|
214
|
+
mode: STEVE_WATCH_EVENT.CHANGES,
|
|
215
|
+
force: true,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
expect(dispatch).toHaveBeenNthCalledWith(1, 'unwatchIncompatible', {
|
|
219
|
+
id: undefined, mode: STEVE_WATCH_EVENT.CHANGES, namespace: undefined, selector: undefined, type: obj.type
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
expect(dispatch).toHaveBeenNthCalledWith(2, 'send', {
|
|
223
|
+
debounceMs: 4000,
|
|
224
|
+
mode: 'resource.changes',
|
|
225
|
+
resourceType: obj.type,
|
|
226
|
+
resourceVersion: revision.toString(),
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Receive start from BE
|
|
230
|
+
actions['ws.resource.start']({
|
|
231
|
+
state, dispatch, getters, commit
|
|
232
|
+
}, { ...msg });
|
|
233
|
+
|
|
234
|
+
expect(dispatch).toHaveBeenCalledTimes(2);
|
|
235
|
+
dispatch.mockClear();
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const errorWatch = ({
|
|
239
|
+
ctx,
|
|
240
|
+
obj, msg,
|
|
241
|
+
}) => {
|
|
242
|
+
const {
|
|
243
|
+
state, dispatch, getters, commit
|
|
244
|
+
} = ctx;
|
|
245
|
+
|
|
246
|
+
// Receive error from BE
|
|
247
|
+
actions['ws.resource.error']({
|
|
248
|
+
dispatch, getters, commit
|
|
249
|
+
}, {
|
|
250
|
+
...msg,
|
|
251
|
+
data: { error: 'too old' }
|
|
252
|
+
});
|
|
253
|
+
expect(state.inError).toStrictEqual(
|
|
254
|
+
{
|
|
255
|
+
'type=abc,namespace=,id=,selector=': {
|
|
256
|
+
obj: {
|
|
257
|
+
type: msg.resourceType,
|
|
258
|
+
mode: msg.mode,
|
|
259
|
+
},
|
|
260
|
+
reason: REVISION_TOO_OLD
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
// Receive stop from BE
|
|
266
|
+
actions['ws.resource.stop']({
|
|
267
|
+
state, dispatch, getters, commit
|
|
268
|
+
}, { ...msg });
|
|
269
|
+
// stop tries to watch again, however we're in error so will be ignored
|
|
270
|
+
expect(dispatch).toHaveBeenNthCalledWith(1, 'watch', {
|
|
271
|
+
id: undefined, mode: STEVE_WATCH_EVENT.CHANGES, namespace: undefined, selector: undefined, type: obj.type
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
dispatch.mockClear();
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const cycleFail = async({
|
|
278
|
+
ctx,
|
|
279
|
+
obj, msg,
|
|
280
|
+
revision,
|
|
281
|
+
tooManyTries = false,
|
|
282
|
+
}) => {
|
|
283
|
+
const { dispatch } = ctx;
|
|
284
|
+
|
|
285
|
+
startWatch({
|
|
286
|
+
ctx, obj, msg, revision
|
|
287
|
+
});
|
|
288
|
+
errorWatch({
|
|
289
|
+
ctx, obj, msg
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
await waitForBackOff(50000);
|
|
293
|
+
await waitForBackOff(50000);
|
|
294
|
+
|
|
295
|
+
if (tooManyTries) {
|
|
296
|
+
expect(dispatch).toHaveBeenCalledTimes(0);
|
|
297
|
+
} else {
|
|
298
|
+
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
299
|
+
expect(dispatch).toHaveBeenCalledWith('resyncWatch', {
|
|
300
|
+
...msg,
|
|
301
|
+
data: { error: 'too old' }
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
await waitForBackOff();
|
|
306
|
+
|
|
307
|
+
if (tooManyTries) {
|
|
308
|
+
expect(dispatch).toHaveBeenCalledTimes(0);
|
|
309
|
+
} else {
|
|
310
|
+
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
dispatch.mockClear();
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const cycleSucceed = async({
|
|
317
|
+
ctx,
|
|
318
|
+
obj, msg,
|
|
319
|
+
revision
|
|
320
|
+
}) => {
|
|
321
|
+
const { dispatch } = ctx;
|
|
322
|
+
|
|
323
|
+
dispatch.mockImplementation(async(type: string) => {
|
|
324
|
+
if (type === 'resyncWatch') {
|
|
325
|
+
return Promise.resolve();
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
startWatch({
|
|
330
|
+
ctx, obj, msg, revision
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
await waitForBackOff();
|
|
334
|
+
|
|
335
|
+
expect(dispatch).toHaveBeenCalledTimes(0);
|
|
336
|
+
|
|
337
|
+
await waitForBackOff();
|
|
338
|
+
|
|
339
|
+
expect(dispatch).toHaveBeenCalledTimes(0);
|
|
340
|
+
|
|
341
|
+
dispatch.mockClear();
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const dispatch = jest.fn();
|
|
345
|
+
const rootGetters = {
|
|
346
|
+
'type-map/isSpoofed': () => false,
|
|
347
|
+
'management/byId': () => ({ value: true })
|
|
348
|
+
};
|
|
349
|
+
const obj = { type: 'abc' };
|
|
350
|
+
const msg = {
|
|
351
|
+
resourceType: obj.type,
|
|
352
|
+
mode: STEVE_WATCH_EVENT.CHANGES,
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const initStore = () => {
|
|
356
|
+
const state = { started: [], inError: {} };
|
|
357
|
+
const _getters = {
|
|
358
|
+
normalizeType: (type: string) => type,
|
|
359
|
+
schemaFor: () => ({}),
|
|
360
|
+
storeName: 'test',
|
|
361
|
+
inError: (...args) => getters.inError(state)(...args),
|
|
362
|
+
watchStarted: (...args) => getters.watchStarted(state)(...args),
|
|
363
|
+
backOffId: (...args) => getters.backOffId()(...args),
|
|
364
|
+
canBackoff: () => true,
|
|
365
|
+
};
|
|
366
|
+
const commit = (type, ...args) => mutations[type](state, ...args);
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
state, dispatch, getters: _getters, rootGetters, commit
|
|
370
|
+
};
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
beforeAll(() => {
|
|
374
|
+
jest.useFakeTimers();
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
afterEach(() => {
|
|
378
|
+
backOff.resetAll();
|
|
379
|
+
dispatch.mockClear();
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// eslint-disable-next-line jest/expect-expect
|
|
383
|
+
it('succeeds', async() => {
|
|
384
|
+
jest.useFakeTimers();
|
|
385
|
+
|
|
386
|
+
const ctx = initStore();
|
|
387
|
+
|
|
388
|
+
await cycleSucceed({
|
|
389
|
+
ctx, msg, obj, revision: 1
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// eslint-disable-next-line jest/expect-expect
|
|
394
|
+
it('succeeds after a few failures', async() => {
|
|
395
|
+
jest.useFakeTimers();
|
|
396
|
+
|
|
397
|
+
const ctx = initStore();
|
|
398
|
+
|
|
399
|
+
await cycleFail({
|
|
400
|
+
ctx, msg, obj, revision: 1
|
|
401
|
+
});
|
|
402
|
+
await cycleFail({
|
|
403
|
+
ctx, msg, obj, revision: 1
|
|
404
|
+
});
|
|
405
|
+
await cycleFail({
|
|
406
|
+
ctx, msg, obj, revision: 1
|
|
407
|
+
});
|
|
408
|
+
await cycleFail({
|
|
409
|
+
ctx, msg, obj, revision: 1
|
|
410
|
+
});
|
|
411
|
+
await cycleSucceed({
|
|
412
|
+
ctx, msg, obj, revision: 1
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
// eslint-disable-next-line jest/expect-expect
|
|
417
|
+
it('never succeeds', async() => {
|
|
418
|
+
const ctx = initStore();
|
|
419
|
+
|
|
420
|
+
for (let i = 0; i < 10; i++) {
|
|
421
|
+
await cycleFail({
|
|
422
|
+
ctx, msg, obj, revision: 1
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
await cycleFail({
|
|
427
|
+
ctx, msg, obj, revision: 1, tooManyTries: true
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
});
|
|
174
432
|
});
|
package/plugins/steve/getters.js
CHANGED
|
@@ -154,9 +154,15 @@ export default {
|
|
|
154
154
|
opt.excludeFields = Array.isArray(opt?.omitExcludeFields) ? excludeFields.filter((f) => !f.includes(opt.omitExcludeFields)) : excludeFields;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
if (opt.excludeFields.length) {
|
|
158
|
+
const excludeParamsString = opt.excludeFields.map((field) => `exclude=${ field }`).join('&');
|
|
158
159
|
|
|
159
|
-
|
|
160
|
+
url += `${ url.includes('?') ? '&' : '?' }${ excludeParamsString }`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (opt.revision) {
|
|
164
|
+
url += `${ url.includes('?') ? '&' : '?' }${ `revision=${ opt.revision }` }`;
|
|
165
|
+
}
|
|
160
166
|
}
|
|
161
167
|
// End: Exclude
|
|
162
168
|
|
|
@@ -36,12 +36,19 @@ export const WATCH_STATUSES = {
|
|
|
36
36
|
REMOVE_REQUESTED: 'removed_requested'
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Create a unique key for a specific resource watch's params
|
|
41
|
+
*/
|
|
39
42
|
export const keyForSubscribe = ({
|
|
40
43
|
resourceType, type, namespace, id, selector
|
|
41
44
|
} = {}) => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
const keyMap = {
|
|
46
|
+
type: resourceType || type, namespace, id, selector
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return Object.entries(keyMap)
|
|
50
|
+
.map(([prop, value]) => `${ prop }=${ value || '' }`)
|
|
51
|
+
.join(',');
|
|
45
52
|
};
|
|
46
53
|
|
|
47
54
|
export const watchKeyFromMessage = (msg) => {
|