@rancher/shell 3.0.12-rc.4 → 3.0.12-rc.5

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 (81) hide show
  1. package/assets/styles/global/_button.scss +1 -1
  2. package/assets/translations/en-us.yaml +39 -10
  3. package/components/ActionDropdownShell.vue +5 -3
  4. package/components/ButtonGroup.vue +26 -1
  5. package/components/CruResource.vue +51 -2
  6. package/components/PromptRestore.vue +93 -32
  7. package/components/Questions/index.vue +1 -0
  8. package/components/ResourceTable.vue +1 -0
  9. package/components/SortableTable/index.vue +4 -3
  10. package/components/Wizard.vue +14 -1
  11. package/components/__tests__/ButtonGroup.test.ts +56 -0
  12. package/components/__tests__/PromptRestore.test.ts +169 -19
  13. package/components/fleet/GitRepoAdvancedTab.vue +1 -0
  14. package/components/fleet/GitRepoMetadataTab.vue +5 -0
  15. package/components/fleet/HelmOpAppCoConfigTab.vue +4 -0
  16. package/components/fleet/HelmOpMetadataTab.vue +5 -0
  17. package/components/form/FileSelector.vue +39 -1
  18. package/components/form/PrivateRegistry.constants.ts +7 -0
  19. package/components/form/PrivateRegistry.vue +253 -18
  20. package/components/form/SelectOrCreateAuthSecret.vue +140 -17
  21. package/components/form/__tests__/FileSelector.test.ts +23 -0
  22. package/components/form/__tests__/PrivateRegistry.test.ts +463 -73
  23. package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +122 -0
  24. package/components/formatter/EtcdSnapshotName.vue +73 -0
  25. package/components/nav/Header.vue +8 -1
  26. package/components/templates/default.vue +7 -0
  27. package/config/features.js +1 -0
  28. package/config/labels-annotations.js +2 -0
  29. package/config/product/manager.js +6 -0
  30. package/config/secret.ts +10 -0
  31. package/config/settings.ts +6 -2
  32. package/config/types.js +7 -0
  33. package/detail/provisioning.cattle.io.cluster.vue +79 -3
  34. package/dialog/RotateEncryptionKeyDialog.vue +33 -9
  35. package/dialog/__tests__/RotateEncryptionKeyDialog.test.ts +78 -0
  36. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +92 -0
  37. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +101 -0
  38. package/edit/__tests__/management.cattle.io.setting.test.ts +2 -1
  39. package/edit/compliance.cattle.io.clusterscanprofile.vue +39 -41
  40. package/edit/fleet.cattle.io.gitrepo.vue +70 -16
  41. package/edit/fleet.cattle.io.helmop.vue +51 -5
  42. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  43. package/edit/{management.cattle.io.setting.vue → management.cattle.io.setting/index.vue} +32 -9
  44. package/edit/management.cattle.io.setting/system-default-registry-pull-secrets.vue +81 -0
  45. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -12
  46. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +18 -0
  47. package/edit/provisioning.cattle.io.cluster/rke2.vue +5 -1
  48. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +0 -1
  49. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +14 -55
  50. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +156 -0
  51. package/models/__tests__/secret.test.ts +68 -1
  52. package/models/management.cattle.io.cluster.js +21 -3
  53. package/models/pod.js +13 -2
  54. package/models/provisioning.cattle.io.cluster.js +59 -9
  55. package/models/rke.cattle.io.etcdsnapshot.js +17 -9
  56. package/models/secret.js +19 -0
  57. package/models/workload.js +12 -7
  58. package/package.json +1 -1
  59. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +485 -107
  60. package/pages/c/_cluster/apps/charts/install.vue +114 -28
  61. package/pkg/require-asset.lib.js +25 -0
  62. package/pkg/vue.config.js +7 -0
  63. package/plugins/dashboard-store/__tests__/resource-class.test.ts +84 -0
  64. package/plugins/dashboard-store/getters.js +0 -1
  65. package/plugins/dashboard-store/resource-class.js +52 -12
  66. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +30 -0
  67. package/rancher-components/Form/TextArea/__tests__/TextAreaAutoGrow.test.ts +95 -0
  68. package/rancher-components/RcButton/index.ts +1 -1
  69. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +6 -1
  70. package/store/__tests__/features.test.ts +131 -0
  71. package/store/__tests__/growl.test.ts +374 -0
  72. package/store/__tests__/modal.test.ts +131 -0
  73. package/store/__tests__/slideInPanel.test.ts +88 -0
  74. package/store/__tests__/type-map.utils.test.ts +433 -0
  75. package/store/features.js +4 -0
  76. package/types/shell/index.d.ts +62 -0
  77. package/utils/__tests__/operation-cr.test.ts +34 -0
  78. package/utils/operation-cr.js +19 -0
  79. package/utils/require-asset.ts +7 -0
  80. package/utils/validators/__tests__/private-registry.test.ts +27 -15
  81. package/utils/validators/private-registry.ts +15 -4
@@ -8,7 +8,7 @@ $btn-sm-height: 30px;
8
8
  // -----------------------------------------------------------------------------
9
9
  .btn,
10
10
  button,
11
- [class^='btn-'] {
11
+ [class^='btn-']:not(.btn-group) {
12
12
  align-items: center;
13
13
  display: inline-flex;
14
14
  text-align: center;
@@ -72,6 +72,7 @@ generic:
72
72
  warning: Warning
73
73
  error: Error
74
74
  ok: OK
75
+ or: or
75
76
  other: |-
76
77
  {count, plural,
77
78
  one {other}
@@ -1007,6 +1008,7 @@ asyncButton:
1007
1008
  action: Snapshot Now
1008
1009
  waiting: Snapshot Initiated…
1009
1010
  success: Snapshot Creating
1011
+ day2OpsNotEnabled: Day 2 Operations are not enabled for this cluster
1010
1012
  timing:
1011
1013
  action: Generate Response Times
1012
1014
  waiting: Generating…
@@ -1138,9 +1140,15 @@ catalog:
1138
1140
  label: Container Registry
1139
1141
  tooltip: Container images are pulled from the Cluster Container Registry or, failing that, the System Container Registry Setting. To change this default behavior enter or update the registry here
1140
1142
  custom:
1141
- checkBoxLabel: Container Registry for Rancher System Container Images
1143
+ checkBoxLabel: Override the Default Container Registry
1142
1144
  inputLabel: Container Registry
1143
1145
  placeholder: Registry domain and ports, ex. registry.io:5000
1146
+ pullSecret:
1147
+ skipOption: Do not use image pull secrets
1148
+ defaultLabel: 'Use default pull secret ({name})'
1149
+ defaultLabelGeneric: Use default pull secrets
1150
+ existingValuesBanner: '{secrets} are configured as image pull secrets in the chart values. To modify them, edit the values YAML directly.'
1151
+ defaultSecretsBanner: '{secrets} are configured as default pull secrets. Select or create an image pull secret here to override the default.'
1144
1152
  header:
1145
1153
  charts: Charts
1146
1154
  info:
@@ -2680,6 +2688,7 @@ cluster:
2680
2688
  other {A snapshot has been requested for {count} clusters}
2681
2689
  }
2682
2690
  groupLabel: Location
2691
+ predatesImportTooltip: The restore action is not currently supported for this snapshot as it predates the import into Rancher.
2683
2692
  failed: "Snapshot from {time} failed"
2684
2693
  rke1:
2685
2694
  local: local
@@ -2744,6 +2753,7 @@ cluster:
2744
2753
  upgrade: Upgrade Strategy
2745
2754
  registration: Registration
2746
2755
  nodePools: Node Pools
2756
+ operations: Operations
2747
2757
  rotateCertificates:
2748
2758
  label: Rotate Certificates
2749
2759
  modalTitle: Rotate Cluster Certificates
@@ -2984,10 +2994,10 @@ fleet:
2984
2994
  title: Continuous Delivery Settings
2985
2995
  info: Rancher will reboot Fleet agent and controller on settings change.
2986
2996
  apply: Apply changes
2987
- noPermissions: You have no permissions to modify Fleet Settings
2997
+ noPermissions: You have no permissions to modify Continuous Delivery Settings
2988
2998
  parseError: 'Cannot parse values from "{ path }" in "{ id }" ConfigMap'
2989
2999
  fields:
2990
- ariaLabel: Fleet {name} setting
3000
+ ariaLabel: Continuous Delivery {name} setting
2991
3001
  agentTLSMode:
2992
3002
  label: TLS Mode
2993
3003
  description: "Determines whether the agent should trust CA bundles from the operating system's trust store when connecting to a management cluster."
@@ -3064,13 +3074,13 @@ fleet:
3064
3074
  description: 'Agent deployment settings.'
3065
3075
  replicas:
3066
3076
  label: Replicas
3067
- description: 'Number of replicas of Fleet pods.'
3077
+ description: 'Number of replicas of pods.'
3068
3078
  annotations:
3069
3079
  label: Extra Annotations
3070
- description: 'Extra annotations passed to the Fleet pods.'
3080
+ description: 'Extra annotations passed to the pods.'
3071
3081
  developer:
3072
3082
  label: Developer
3073
- description: 'Enable debug info from Fleet.'
3083
+ description: 'Enable debug info.'
3074
3084
 
3075
3085
  tableHeaders:
3076
3086
  applicationType: Type
@@ -3081,7 +3091,7 @@ fleet:
3081
3091
  dashboard:
3082
3092
  pageTitle: Continuous Delivery Dashboard
3083
3093
  menuLabel: Dashboard
3084
- welcome: Welcome to Fleet Continuous Delivery
3094
+ welcome: Welcome to Continuous Delivery
3085
3095
  gitOpsScale: GitOps at scale.
3086
3096
  learnMore: Learn More.
3087
3097
  learnMoreLink: https://fleet.rancher.io
@@ -3204,7 +3214,7 @@ fleet:
3204
3214
  groupBy: Group By Type
3205
3215
  subTypes:
3206
3216
  fleet.cattle.io.gitrepo:
3207
- description: GitRepo describes a git repository that is watched by Fleet. The resource contains the necessary information to deploy the repo, or parts of it, to target clusters.
3217
+ description: GitRepo describes a git repository that is watched. The resource contains the necessary information to deploy the repo, or parts of it, to target clusters.
3208
3218
  fleet.cattle.io.helmop:
3209
3219
  description: HelmOp is a simplified way of creating bundles by directly pointing to a Helm repository or to an OCI registry, without needing to set up a git repository.
3210
3220
  suse-application-collection:
@@ -6025,6 +6035,13 @@ promptRestore:
6025
6035
  fromS3: Restore from S3
6026
6036
  label: Snapshot
6027
6037
  placeholder: Select a snapshot to restore
6038
+ error:
6039
+ unableToResolveTargetCluster: Unable to resolve target cluster for snapshot restore
6040
+ restoreMode:
6041
+ label: Restore Type
6042
+ onlyEtcd: Only etcd
6043
+ kubernetesVersionAndEtcd: Kubernetes version and etcd
6044
+ clusterConfigKubernetesVersionAndEtcd: Cluster config, Kubernetes version and etcd
6028
6045
  notification:
6029
6046
  title: Restore Snapshot
6030
6047
  message: Restoring snapshot { selectedSnapshot } has started...
@@ -6048,7 +6065,9 @@ promptRotateEncryptionKey:
6048
6065
  title: Rotate Encryption Keys
6049
6066
  description: The last backup {name} was performed on {date}
6050
6067
  warning: Before proceeding, ensure a successful ETCD backup of the cluster has been completed.
6051
- error: No backup found
6068
+ error:
6069
+ noBackup: No backup found
6070
+ unableToResolveTargetCluster: Unable to resolve target cluster for encryption key rotation
6052
6071
 
6053
6072
  rancherAlertingDrivers:
6054
6073
  msTeams: Enable Microsoft Teams
@@ -6333,6 +6352,8 @@ resourceYaml:
6333
6352
 
6334
6353
  secret:
6335
6354
  authentication: Authentication
6355
+ githubApp:
6356
+ label: GitHub App
6336
6357
  certificate:
6337
6358
  certificate: Certificate
6338
6359
  certificates: Certificates
@@ -6469,14 +6490,19 @@ selectOrCreateAuthSecret:
6469
6490
  passwordPersonalAccessToken: Password/Personal Access Token
6470
6491
  rke:
6471
6492
  info: "An RKE Auth Config secret contains the username and password concatenated and base64 encoded into the secret's 'auth' key"
6493
+ githubApp:
6494
+ appId: GitHub App ID
6495
+ installationId: GitHub App Installation ID
6496
+ privateKey: GitHub App Private Key
6472
6497
  namespaceGroup: "Namespace: {name}"
6473
6498
  chooseExisting: "Choose an existing secret:"
6474
6499
  createSsh: Create an SSH Key Secret
6475
6500
  createBasic: Create an HTTP Basic Auth Secret
6476
6501
  createS3: Create an S3-Compatible Auth Secret
6477
6502
  createRKE: Create an RKE Auth Config Secret
6503
+ createGithubApp: Create a GitHub App Auth Secret
6478
6504
  createImagePullSecretBasedOnAuth: Create an Image Pull Secret based on Authentication Secret
6479
- createImagePullSecret: Create a new Image Pull Secret with new Username/Password
6505
+ createImagePullSecret: Create an Image Pull Secret with a Username and Password
6480
6506
 
6481
6507
  serviceAccount:
6482
6508
  automount: Automount Service Account Token
@@ -7363,6 +7389,7 @@ validation:
7363
7389
  betweenValues: '"{key}" must be between {min} and {max}'
7364
7390
  noSchema: No schema found to validate
7365
7391
  noType: No type to validate
7392
+ createResourceFailed: 'Failed to create resource: insufficient permissions or resource type not found'
7366
7393
  number:
7367
7394
  requiredInt: '"{key}" must be integer'
7368
7395
  isPositive: '"{key}" must be positive'
@@ -8966,6 +8993,7 @@ advancedSettings:
8966
8993
  'ingress-ip-domain': 'Wildcard DNS domain to use for automatically generated Ingress hostnames. <ingress-name>.<namespace-name>.<ip address of ingress controller> will be added to the domain.'
8967
8994
  'server-url': 'Default {appName} install url. Must be HTTPS. All nodes in your cluster must be able to reach this.'
8968
8995
  'system-default-registry': 'Private registry to be used for all Rancher System Container Images. If no value is specified, the default registry for the container runtime is used. For Docker and containerd, the default is `docker.io`.'
8996
+ 'system-default-registry-pull-secrets': 'List of image pull secrets to authenticate into registry from which Rancher System Container Images are pulled. By default, these secrets will be copied into each Rancher chart namespace. Secrets must be in the `cattle-system` namespace. The first valid secret listed here will be used.'
8969
8997
  'ui-dashboard-index': 'HTML index location for the {appName} UI.'
8970
8998
  'ui-offline-preferred': 'Controls whether UI assets are served locally by the server container or from the remote URL defined in the ui-dashboard-index setting. The `Dynamic` option will use local assets in production builds of {appName}.'
8971
8999
  'ui-pl': 'Private-Label company name.'
@@ -8988,6 +9016,7 @@ advancedSettings:
8988
9016
  'k3s-based-upgrader-uninstall-concurrency': Defines the maximum number of clusters in which Rancher can concurrently uninstall the legacy `rancher-k3s-upgrader` or `rancher-rke2-upgrader` app from imported or node-driver K3s or RKE2 clusters.
8989
9017
  'system-agent-upgrader-install-concurrency': Defines the maximum number of clusters in which Rancher can concurrently install the resources required for upgrading system-agent.
8990
9018
  'imported-cluster-version-management': Enables version management for imported RKE2/K3s clusters, and the local cluster if it is an RKE2/K3s cluster. The per-cluster version management setting overrides this global setting at the cluster level. For existing clusters where the cluster-level version management is set to 'system-default', changing this flag will trigger a redeployment of the cluster agent during the next reconciliation (by default every 5 minutes, or as soon as the cluster is edited, whichever comes first).
9019
+ 'imported-cluster-day2-ops-enabled': Controls whether newly imported RKE2/K3s clusters will have day 2 operations (etcd snapshots, restores, encryption key rotations) enabled by default. This does not affect previously imported clusters.
8991
9020
  warnings:
8992
9021
  'agent-tls-mode': 'Changing this setting will cause all agents to be redeployed.'
8993
9022
  editHelp:
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { RcDropdown, RcDropdownTrigger, RcDropdownItem } from '@components/RcDropdown';
3
+ import { ButtonSize } from '@components/RcButton';
3
4
  type HiddenAction = {
4
5
  action: string;
5
6
  enabled: boolean;
@@ -11,11 +12,12 @@ type HiddenAction = {
11
12
  anyEnabled: boolean;
12
13
  }
13
14
 
14
- defineProps<{
15
+ withDefaults(defineProps<{
15
16
  disabled: boolean,
16
17
  hiddenActions: HiddenAction[],
17
18
  actionTooltip: unknown,
18
- }>();
19
+ size?: ButtonSize,
20
+ }>(), { size: 'large' });
19
21
 
20
22
  const emit = defineEmits(['click', 'mouseover', 'mouseleave']);
21
23
 
@@ -35,7 +37,7 @@ const setBulkActionOfInterest = (act: HiddenAction | null, event: 'mouseover' |
35
37
  >
36
38
  <rc-dropdown-trigger
37
39
  class="bulk-actions-dropdown"
38
- size="large"
40
+ :size="size"
39
41
  :disabled="disabled"
40
42
  >
41
43
  <template #before>
@@ -31,11 +31,25 @@ export default {
31
31
  disabled: {
32
32
  type: Boolean,
33
33
  default: false,
34
- }
34
+ },
35
+
36
+ size: {
37
+ type: String,
38
+ default: 'large',
39
+ validator: (value) => ['small', 'medium', 'large'].includes(value),
40
+ },
35
41
 
36
42
  },
37
43
 
38
44
  computed: {
45
+ sizeClass() {
46
+ return {
47
+ small: 'btn-sm',
48
+ medium: 'btn-md',
49
+ large: null,
50
+ }[this.size];
51
+ },
52
+
39
53
  optionObjects() {
40
54
  const value = this.value;
41
55
 
@@ -52,6 +66,7 @@ export default {
52
66
 
53
67
  out.class = {
54
68
  btn: true,
69
+ [this.sizeClass]: !!this.sizeClass,
55
70
  [this.inactiveClass]: !active,
56
71
  [this.activeClass]: active,
57
72
  };
@@ -122,3 +137,13 @@ export default {
122
137
  </button>
123
138
  </div>
124
139
  </template>
140
+
141
+ <style lang="scss" scoped>
142
+ .btn-group {
143
+ .btn-md {
144
+ padding: 0 12px;
145
+ min-height: 32px;
146
+ line-height: 32px;
147
+ }
148
+ }
149
+ </style>
@@ -127,6 +127,12 @@ export default {
127
127
  default: () => []
128
128
  },
129
129
 
130
+ // Used to be called before going to the next step in the wizard.
131
+ beforeNext: {
132
+ type: Function,
133
+ default: null
134
+ },
135
+
130
136
  stepsOptions: {
131
137
  type: Object,
132
138
  default: () => ({ editFirstStep: true })
@@ -200,6 +206,7 @@ export default {
200
206
  tocContainerHeight: 0,
201
207
  mainLayoutEl: null,
202
208
  throttledComputeTocContainerHeight: null,
209
+ nextValidating: false,
203
210
  /**
204
211
  * Initialised on demand (given that it needs to make a request to fetch schema definition)
205
212
  */
@@ -488,6 +495,47 @@ export default {
488
495
  return slot !== 'default' && typeof this.$slots[slot] === 'function';
489
496
  },
490
497
 
498
+ async wizardBeforeGoToStep(fromStep, toStep) {
499
+ if (!this.beforeNext) {
500
+ return;
501
+ }
502
+
503
+ const fromIdx = this.steps.findIndex((s) => s.name === fromStep.name);
504
+ const toIdx = this.steps.findIndex((s) => s.name === toStep.name);
505
+
506
+ if (toIdx <= fromIdx) {
507
+ return;
508
+ }
509
+
510
+ try {
511
+ await this.beforeNext(fromStep);
512
+ this.$emit('error', []);
513
+ } catch (err) {
514
+ this.$emit('error', exceptionToErrorsArray(err));
515
+ throw err;
516
+ }
517
+ },
518
+
519
+ async handleNext(nextFn, activeStep) {
520
+ if (!this.beforeNext) {
521
+ nextFn();
522
+
523
+ return;
524
+ }
525
+
526
+ this.nextValidating = true;
527
+
528
+ try {
529
+ await this.beforeNext(activeStep);
530
+ this.$emit('error', []);
531
+ nextFn();
532
+ } catch (err) {
533
+ this.$emit('error', exceptionToErrorsArray(err));
534
+ } finally {
535
+ this.nextValidating = false;
536
+ }
537
+ },
538
+
491
539
  formatError(err) {
492
540
  if ( typeof err === 'string') {
493
541
  return err;
@@ -751,6 +799,7 @@ export default {
751
799
  :edit-first-step="stepsOptions.editFirstStep"
752
800
  :errors="errors"
753
801
  :finish-mode="finishMode"
802
+ :before-go-to-step="wizardBeforeGoToStep"
754
803
  class="wizard"
755
804
  @error="e=>errors = e"
756
805
  >
@@ -834,10 +883,10 @@ export default {
834
883
  name="next"
835
884
  >
836
885
  <button
837
- :disabled="!canNext"
886
+ :disabled="!canNext || nextValidating"
838
887
  type="button"
839
888
  class="btn role-primary"
840
- @click="next()"
889
+ @click="handleNext(next, activeStep)"
841
890
  >
842
891
  <t k="wizard.next" />
843
892
  </button>
@@ -7,16 +7,15 @@ import Date from '@shell/components/formatter/Date.vue';
7
7
  import RadioGroup from '@components/Form/Radio/RadioGroup.vue';
8
8
  import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
9
9
  import { exceptionToErrorsArray } from '@shell/utils/error';
10
- import { CAPI, SNAPSHOT } from '@shell/config/types';
10
+ import { CAPI, SNAPSHOT, OPERATION, MANAGEMENT } from '@shell/config/types';
11
11
  import { set } from '@shell/utils/object';
12
12
  import ChildHook, { BEFORE_SAVE_HOOKS } from '@shell/mixins/child-hook';
13
13
  import { DATE_FORMAT, TIME_FORMAT } from '@shell/store/prefs';
14
14
  import { escapeHtml } from '@shell/utils/string';
15
15
  import day from 'dayjs';
16
16
  import { sortBy } from '@shell/utils/sort';
17
- import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
18
17
  import AppModal from '@shell/components/AppModal.vue';
19
-
18
+ import { createOperationCR } from '@shell/utils/operation-cr';
20
19
  export default {
21
20
  components: {
22
21
  Card,
@@ -66,8 +65,41 @@ export default {
66
65
  return !!this.snapshot;
67
66
  },
68
67
 
69
- isRke2() {
70
- return !!this.snapshot?.rke2;
68
+ targetCluster() {
69
+ if (this.isCluster) {
70
+ return this.toRestore?.[0] || null;
71
+ }
72
+
73
+ if (this.snapshot?.cluster) {
74
+ return this.snapshot.cluster;
75
+ }
76
+
77
+ const snapshotClusterName = this.snapshot?.spec?.clusterName || this.snapshot?.clusterName;
78
+ const snapshotClusterId = this.snapshot?.clusterId || (snapshotClusterName ? `${ this.snapshot?.metadata?.namespace }/${ snapshotClusterName }` : null);
79
+
80
+ if (!snapshotClusterId) {
81
+ return null;
82
+ }
83
+
84
+ return this.$store.getters['management/byId'](CAPI.RANCHER_CLUSTER, snapshotClusterId);
85
+ },
86
+
87
+ targetMgmtCluster() {
88
+ if (this.targetCluster?.mgmt) {
89
+ return this.targetCluster.mgmt;
90
+ }
91
+
92
+ const mgmtClusterId = this.snapshot?.spec?.clusterName;
93
+
94
+ if (!mgmtClusterId) {
95
+ return null;
96
+ }
97
+
98
+ return this.$store.getters['management/byId'](MANAGEMENT.CLUSTER, mgmtClusterId);
99
+ },
100
+
101
+ isImported() {
102
+ return !!(this.targetCluster?.isImported || this.targetMgmtCluster?.isImported);
71
103
  },
72
104
 
73
105
  clusterSnapshots() {
@@ -77,6 +109,13 @@ export default {
77
109
  return [];
78
110
  }
79
111
  },
112
+ restoreModeLabels() {
113
+ return [
114
+ this.t('promptRestore.restoreMode.onlyEtcd'),
115
+ this.t('promptRestore.restoreMode.kubernetesVersionAndEtcd'),
116
+ this.t('promptRestore.restoreMode.clusterConfigKubernetesVersionAndEtcd')
117
+ ];
118
+ },
80
119
  restoreModeOptions() {
81
120
  return ['none', 'kubernetesVersion', 'all'];
82
121
  }
@@ -112,7 +151,7 @@ export default {
112
151
  const promise = this.$store.dispatch('management/findAll', { type: SNAPSHOT }).then((snapshots) => {
113
152
  const toRestoreClusterName = cluster?.clusterName || cluster?.metadata?.name;
114
153
 
115
- return snapshots.filter((s) => s?.snapshotFile?.status === STATES_ENUM.SUCCESSFUL && s.clusterName === toRestoreClusterName
154
+ return snapshots.filter((s) => s?.restoreEnabled && s.clusterName === toRestoreClusterName
116
155
  );
117
156
  });
118
157
 
@@ -143,19 +182,41 @@ export default {
143
182
 
144
183
  async apply(buttonDone) {
145
184
  try {
146
- const cluster = this.$store.getters['management/byId'](CAPI.RANCHER_CLUSTER, this.snapshot.clusterId);
185
+ const cluster = this.targetCluster;
186
+ const mgmtCluster = cluster?.mgmt || this.targetMgmtCluster;
147
187
 
148
- await this.applyHooks(BEFORE_SAVE_HOOKS);
149
-
150
- const now = cluster.spec?.rkeConfig?.etcdSnapshotRestore?.generation || 0;
188
+ const isImportedWithDayTwoOps = cluster?.isImportedWithDayTwoOps || mgmtCluster?.isDayTwoOpsEnabled;
151
189
 
152
- set(cluster, 'spec.rkeConfig.etcdSnapshotRestore', {
153
- generation: now + 1,
154
- name: this.snapshot.name,
155
- restoreRKEConfig: this.restoreMode,
156
- });
190
+ await this.applyHooks(BEFORE_SAVE_HOOKS);
157
191
 
158
- await cluster.save();
192
+ // For imported clusters with day 2 ops enabled, create an operation CR
193
+ if (isImportedWithDayTwoOps) {
194
+ if (!mgmtCluster) {
195
+ throw new Error(this.t('promptRestore.error.unableToResolveTargetCluster'));
196
+ }
197
+ const namespace = mgmtCluster?.id;
198
+ const safePrefix = mgmtCluster?.id;
199
+ const spec = {
200
+ clusterRef: {
201
+ apiVersion: 'management.cattle.io/v3',
202
+ kind: 'Cluster',
203
+ name: mgmtCluster?.id,
204
+ },
205
+ args: { name: this.snapshot?.snapshotFile?.name },
206
+ };
207
+
208
+ createOperationCR(this.$store.dispatch, OPERATION.ETCD_SNAPSHOT_RESTORE, spec, namespace, safePrefix);
209
+ } else {
210
+ const now = cluster.spec?.rkeConfig?.etcdSnapshotRestore?.generation || 0;
211
+
212
+ set(cluster, 'spec.rkeConfig.etcdSnapshotRestore', {
213
+ generation: now + 1,
214
+ name: this.snapshot.name,
215
+ restoreRKEConfig: this.restoreMode,
216
+ });
217
+
218
+ await cluster.save();
219
+ }
159
220
 
160
221
  this.$store.dispatch('growl/success', {
161
222
  title: this.t('promptRestore.notification.title'),
@@ -233,18 +294,25 @@ export default {
233
294
  />
234
295
  </p>
235
296
  </div>
236
- <div class="spacer" />
237
- <RadioGroup
238
- v-model:value="restoreMode"
239
- name="restoreMode"
240
- label="Restore Type"
241
- :labels="['Only etcd', 'Kubernetes version and etcd', 'Cluster config, Kubernetes version and etcd']"
242
- :options="restoreModeOptions"
243
- />
297
+ <div v-if="!isImported">
298
+ <div class="spacer" />
299
+ <RadioGroup
300
+ v-model:value="restoreMode"
301
+ name="restoreMode"
302
+ :label="t('promptRestore.restoreMode.label')"
303
+ :labels="restoreModeLabels"
304
+ :options="restoreModeOptions"
305
+ />
306
+ </div>
244
307
  </form>
245
308
  </div>
246
309
  </template>
247
-
310
+ <Banner
311
+ v-for="(err, i) in errors"
312
+ :key="i"
313
+ color="error"
314
+ :label="err"
315
+ />
248
316
  <template #actions>
249
317
  <div class="dialog-actions">
250
318
  <button
@@ -259,13 +327,6 @@ export default {
259
327
  :disabled="!hasSnapshot"
260
328
  @click="apply"
261
329
  />
262
-
263
- <Banner
264
- v-for="(err, i) in errors"
265
- :key="i"
266
- color="error"
267
- :label="err"
268
- />
269
330
  </div>
270
331
  </template>
271
332
  </Card>
@@ -474,6 +474,7 @@ export default {
474
474
  :value="get(value, q.variable)"
475
475
  :disabled="disabled"
476
476
  :chart-name="chartName"
477
+ :mode="mode"
477
478
  @update:value="update(q.variable, $event)"
478
479
  />
479
480
  </div>
@@ -746,6 +746,7 @@ export default {
746
746
  <ButtonGroup
747
747
  v-model:value="group"
748
748
  :options="_groupOptions"
749
+ size="medium"
749
750
  />
750
751
  </template>
751
752
 
@@ -1125,7 +1125,6 @@ export default {
1125
1125
  v-clean-tooltip="actionTooltip"
1126
1126
  type="button"
1127
1127
  variant="primary"
1128
- size="large"
1129
1128
  :class="{[bulkActionClass]:true}"
1130
1129
  :disabled="!act.enabled"
1131
1130
  :data-testid="componentTestid + '-' + act.action"
@@ -1146,6 +1145,7 @@ export default {
1146
1145
  :disabled="!selectedRows.length"
1147
1146
  :hidden-actions="hiddenActions"
1148
1147
  :action-tooltip="actionTooltip"
1148
+ size="medium"
1149
1149
  @click="applyTableAction"
1150
1150
  @mouseover="setBulkActionOfInterest"
1151
1151
  @mouseleave="setBulkActionOfInterest"
@@ -1158,10 +1158,11 @@ export default {
1158
1158
  :disable-button="!selectedRows.length"
1159
1159
  size="sm"
1160
1160
  >
1161
- <template #button-content>
1161
+ <template #button-content="{ buttonSize }">
1162
1162
  <button
1163
1163
  ref="actionDropDown"
1164
1164
  class="btn bg-primary mr-0"
1165
+ :class="buttonSize"
1165
1166
  :disabled="!selectedRows.length"
1166
1167
  >
1167
1168
  <i class="icon icon-gear" />
@@ -1874,7 +1875,7 @@ export default {
1874
1875
  }
1875
1876
 
1876
1877
  .search-box {
1877
- height: 40px;
1878
+ height: 32px;
1878
1879
  margin-left: 10px;
1879
1880
  min-width: 180px;
1880
1881
  }
@@ -124,6 +124,11 @@ export default {
124
124
  errors: {
125
125
  type: Array,
126
126
  default: null,
127
+ },
128
+
129
+ beforeGoToStep: {
130
+ type: Function,
131
+ default: null
127
132
  }
128
133
  },
129
134
 
@@ -217,7 +222,7 @@ export default {
217
222
  },
218
223
 
219
224
  methods: {
220
- goToStep(number, fromNav) {
225
+ async goToStep(number, fromNav) {
221
226
  if (number < 1) {
222
227
  return;
223
228
  }
@@ -233,6 +238,14 @@ export default {
233
238
  return;
234
239
  }
235
240
 
241
+ if (this.beforeGoToStep && fromNav) {
242
+ try {
243
+ await this.beforeGoToStep(this.activeStep, selected);
244
+ } catch {
245
+ return;
246
+ }
247
+ }
248
+
236
249
  this.activeStep = selected;
237
250
 
238
251
  this.$emit('next', { step: selected });