Skip to content

WIP: [UC Backup] BackupStorageLocation UX improvements#7972

Open
SamuAlfageme wants to merge 7 commits intokubermatic:mainfrom
SamuAlfageme:uc_backup_bsl_enhancements
Open

WIP: [UC Backup] BackupStorageLocation UX improvements#7972
SamuAlfageme wants to merge 7 commits intokubermatic:mainfrom
SamuAlfageme:uc_backup_bsl_enhancements

Conversation

@SamuAlfageme
Copy link
Copy Markdown
Contributor

@SamuAlfageme SamuAlfageme commented Apr 3, 2026

What this PR does / why we need it:

This introduces a few UX improvements on the handling of BackupStorageLocations (BSLs) for the UC Backup feature. These apply to both, the Cluster Creation Wizard and "Edit cluster" dialogue.

  • Filter only 'available' BSLs on the dropdown selector.
  • New '+ Create Backup Storage Location' option.
Available BSLs   Add new
Edit dialog

Edit cluster dialog, BSL dropdown

  • Add field validations on the BSL form(s):
    • Basic regexp validation for DNS on 'Region' and 'Endpoint URL' (+ http(s) for the latter).
Region   Endpoint URLs
  • Mandatory 'Endpoint' & 'Region' unless using 'custom config' (see behavior in gif below).
  • Allow to copy BSL error messages on click from the BackupStorageLocation list view
  • Fix: reorder BSL selector & Skip router reconciliation on the 'Edit cluster' modal: the checkbox to enable UC Backup and the BSL dropdown were split by the new 'Skip router reconciliation' on OpenStack DCs

Which issue(s) this PR fixes: N/A

What type of PR is this?
/kind design

Special notes for your reviewer:

Does this PR introduce a user-facing change? Then add your Release Note here:

Cluster Creation/Edition: Improve BackupStorageLocation UX: display only available BSLs and allow to create new ones.

Documentation:

NONE

@kubermatic-bot kubermatic-bot added docs/none Denotes a PR that doesn't need documentation (changes). release-note Denotes a PR that will be considered when it comes time to generate release notes. kind/design Categorizes issue or PR as related to design. labels Apr 3, 2026
@kubermatic-bot
Copy link
Copy Markdown
Contributor

Adding the "do-not-merge/test-issue-needed" label because no test-issue block was detected, please add a proper test-issue block to remove it.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@kubermatic-bot kubermatic-bot added the do-not-merge/test-issue-needed Indicates that a PR should not merge because it's missing one of the test issue labels. label Apr 3, 2026
@kubermatic-bot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign khizerrehan for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubermatic-bot kubermatic-bot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Apr 3, 2026
@kubermatic-bot
Copy link
Copy Markdown
Contributor

Hi @SamuAlfageme. Thanks for your PR.

I'm waiting for a kubermatic member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@kubermatic-bot kubermatic-bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Apr 3, 2026
@SamuAlfageme SamuAlfageme changed the title BackupStorageLocation UX [UC Backup] BackupStorageLocation UX improvements Apr 3, 2026
@kubermatic-bot kubermatic-bot added the dco-signoff: no Denotes that at least one commit in the pull request doesn't have a valid DCO signoff message. label Apr 3, 2026
@SamuAlfageme SamuAlfageme force-pushed the uc_backup_bsl_enhancements branch from 231fbb2 to fc501a5 Compare April 3, 2026 01:14
@kubermatic-bot kubermatic-bot added dco-signoff: yes Denotes that all commits in the pull request have the valid DCO signoff message. and removed dco-signoff: no Denotes that at least one commit in the pull request doesn't have a valid DCO signoff message. labels Apr 3, 2026
@KhizerRehan
Copy link
Copy Markdown
Contributor

/ok-to-test

@kubermatic-bot kubermatic-bot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Apr 3, 2026
@KhizerRehan
Copy link
Copy Markdown
Contributor

@SamuAlfageme can your run npm run fix command and push after linting fixes

@SamuAlfageme SamuAlfageme force-pushed the uc_backup_bsl_enhancements branch from fc501a5 to 85b3894 Compare April 7, 2026 14:43
@kubermatic-bot kubermatic-bot added dco-signoff: no Denotes that at least one commit in the pull request doesn't have a valid DCO signoff message. and removed dco-signoff: yes Denotes that all commits in the pull request have the valid DCO signoff message. labels Apr 7, 2026
@SamuAlfageme SamuAlfageme force-pushed the uc_backup_bsl_enhancements branch from 85b3894 to 3d3f94e Compare April 7, 2026 14:44
@kubermatic-bot kubermatic-bot added dco-signoff: yes Denotes that all commits in the pull request have the valid DCO signoff message. dco-signoff: no Denotes that at least one commit in the pull request doesn't have a valid DCO signoff message. and removed dco-signoff: no Denotes that at least one commit in the pull request doesn't have a valid DCO signoff message. dco-signoff: yes Denotes that all commits in the pull request have the valid DCO signoff message. labels Apr 7, 2026
  - Filter by 'available' BackupStorageLocation.
  - New '+ Create Backup Storage Location' option.

Signed-off-by: Samuel Alfageme Sainz <samuel@alfage.me>
... apply to BSL Creation and Edition:

- DNS validation for 'Region' and 'Endpoint URL' (& http(s) for the latter)
- Explicit "Optional" on 'Access Key ID' and 'Secret Access Key' for anonymous
  login
- Allow to copy BSL error messages on click from the BackupStorageLocation view

Signed-off-by: Samuel Alfageme Sainz <samuel@alfage.me>
You can expect the user knows what it's doing while using 'custom config' so,
    no need to enforce string validation on the custom YAML

Signed-off-by: Samuel Alfageme Sainz <samuel@alfage.me>
... on the 'Edit cluster' modal: the checkbox to enable UC Backup and the BSL
dropdown were split by the new 'Skip router reconciliation' on OpenStack DCs

Signed-off-by: Samuel Alfageme Sainz <samuel@alfage.me>
Replicate the same behaviour from the cluster creation wizard:

- '+ Create Backup Storage Location' (modal on top of modal)
- Filter by 'available' BSLs on the dropdown

Signed-off-by: Samuel Alfageme Sainz <samuel@alfage.me>
Signed-off-by: Samuel Alfageme Sainz <samuel@alfage.me>
@SamuAlfageme SamuAlfageme force-pushed the uc_backup_bsl_enhancements branch from 3b3b6f0 to d663049 Compare April 8, 2026 14:33
@kubermatic-bot kubermatic-bot added dco-signoff: yes Denotes that all commits in the pull request have the valid DCO signoff message. and removed dco-signoff: no Denotes that at least one commit in the pull request doesn't have a valid DCO signoff message. labels Apr 8, 2026
@SamuAlfageme SamuAlfageme force-pushed the uc_backup_bsl_enhancements branch from d663049 to d0e88a8 Compare April 8, 2026 14:45
Dynamical imports for AddBackupStorageLocationDialogComponent on the wizard and
the edit-cluster dialog to fix the CI tests.

Signed-off-by: Samuel Alfageme Sainz <samuel@alfage.me>
@SamuAlfageme SamuAlfageme force-pushed the uc_backup_bsl_enhancements branch from d0e88a8 to 0f3bafe Compare April 8, 2026 18:04
@ahmadhamzh ahmadhamzh self-requested a review April 9, 2026 07:01
<mat-option [value]="bsl.name">{{bsl.displayName}}
</mat-option>
}
<mat-option [value]="createBackupStorageLocationOptionValue">+ Create Backup Storage Location</mat-option>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think adding an option to create a new BSL inside the dropdown is the right approach. I’d prefer something similar to how we handle SSH keys.

I think something like this makes more sense:
Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! I forgot this pattern exists already somewhere in the Dashboard. I'll adapt the PR to use it too 👍

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ahmadhamzh btw, for the "edit UC" view, opening the 'Create BSL' modal over the 'Edit Cluster' modal is something that is not done somewhere else in the Dashboard IIRC, does that work for you?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point — I think we shouldn’t have that at all. So for cluster editing, we shouldn’t include an option to add a storage location at least for now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, dialog over a dialog is not a problem because i have seen this sort of behaviour in other applicaiton when supporting inline option e.g add-bsl dialog but I think what Ahmed said we shouldn't provide this option for edit cluster?

But I am also thinking what if there are existing cluster and need to backup in different locaiton how those scenario would be handled?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like suggestion what ahmed has suggested of adding "+ Add BSL Button" which is better instead of adding inside Dropdown option

  • More clear/explicit
  • And we can opt this change adding behaviour for wizard (if not going for edit dialog)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I am also thinking what if there are existing cluster and need to backup in different locaiton how those scenario would be handled?

users can add them from the cluster backups > Storage Locations and then use them in the edit dialog

});
}

async onBackupStorageLocationSelectionChange(event: MatSelectChange<string>): Promise<void> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Async/await is working fine, but since the rest of the component uses RxJS pipelines, I think it’s better to stay consistent with that approach.

Comment on lines +558 to +568

const AddBackupStorageLocationDialogComponent = await DynamicModule.AddBackupStorageLocationDialogComponent;
if (!AddBackupStorageLocationDialogComponent) {
return;
}
this._matDialog
.open(AddBackupStorageLocationDialogComponent, {
data: {projectID: this.projectID},
})
.afterClosed()
.pipe(take(1), filter(Boolean))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like this would be more consistent with the rest of the code.

Suggested change
const AddBackupStorageLocationDialogComponent = await DynamicModule.AddBackupStorageLocationDialogComponent;
if (!AddBackupStorageLocationDialogComponent) {
return;
}
this._matDialog
.open(AddBackupStorageLocationDialogComponent, {
data: {projectID: this.projectID},
})
.afterClosed()
.pipe(take(1), filter(Boolean))
from(DynamicModule.AddBackupStorageLocationDialogComponent)
.pipe(
filter(Boolean),
switchMap(component =>
this._matDialog.open(component, {data: {projectID: this.projectID}}).afterClosed()
),
take(1),
filter(Boolean),
)

}

private _isBackupStorageLocationAvailable(bsl: BackupStorageLocation): boolean {
const status = bsl.status?.phase || bsl.spec?.status || '';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think we need to check for status cause it will never be available

Suggested change
const status = bsl.status?.phase || bsl.spec?.status || '';
return bsl.status?.phase.toLowerCase() === 'available'

return bsl;
}

private _dnsNameValidator(): ValidatorFn {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually add validators in src/app/shared/validators

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do have a file shared/validators/others.ts where have defined all regex in case needed in other place IMO, regex that is reusable can be put into this file

let me wdyt?

Copy link
Copy Markdown
Contributor

@ahmadhamzh ahmadhamzh Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well after another look i don't think we need this method just to repeat the same regex check.
we can update the regex value to include the .

Copy link
Copy Markdown
Contributor

@KhizerRehan KhizerRehan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feedback(PTAL)

return bsl;
}

private _dnsNameValidator(): ValidatorFn {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do have a file shared/validators/others.ts where have defined all regex in case needed in other place IMO, regex that is reusable can be put into this file

let me wdyt?

}

const labels = value.split('.');
return labels.every(label => this._dnsLabelRegex.test(label)) ? null : {invalidDnsName: true};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to double confirm?

values like

  • us-east-1 ✅
  • us east 1 ❌
  • us-east-1- ❌
  • _us-east-1 ❌

are not valid DNS

return null;
}

if (!/^https?:\/\//i.test(value)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to double confirm if following values are not valid test value?

  • http://minio.local. ❌ (FQDN trailing dot rejected before)
  • https://[::1]:9000 (IPv6) ❌
  • https://s3_internal.lan:9000 (underscore host) ❌

private _isBackupStorageLocationAvailable(bsl: BackupStorageLocation): boolean {
const status = bsl.status?.phase || bsl.spec?.status || '';
return status.toLowerCase() === 'available';
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI:
This comment should be taken into consideraiton incase we OPT to choose to changes in (Edit Cluster Dialog

Otherwise ignore this refactoring

I see this method duplicate can we move to src/app/shared/entity/backup.ts path wdyt?

I was checking codebase something we are doing

export namespace HealthState {
like that using namespaces concept.

Ideally, i though it shouldn't be part of entity/ folder bcz IMO, we have kept all classes or interfaces but also it make sense to keep backup relateed things there even if there are shared utils as like defined here
src/app/shared/utils

something like we are doing here

export function generateEncryptionKey(): string {

as this method is used in both place

  • wizard
  • edit cluster dialog

})
export class AddBackupStorageLocationDialogComponent implements OnInit, OnDestroy {
private readonly _unsubscribe = new Subject<void>();
private readonly _dnsLabelRegex = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be change to include the . and then we don't need to use _dnsNameValidator() method.
we can add
export const DNS_VALIDATOR = Validators.pattern(/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i)

to the shared/validators/others.ts file

[Controls.Region]: this._builder.control(this._config.bslObject?.spec.config?.region ?? ''),
[Controls.Endpoints]: this._builder.control(this._config.bslObject?.spec.config?.s3Url ?? ''),
[Controls.Region]: this._builder.control(this._config.bslObject?.spec.config?.region ?? '', [
this._dnsNameValidator(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this._dnsNameValidator(),
DNS_VALIDATOR,


try {
const url = new URL(value);
if (!['http:', 'https:'].includes(url.protocol)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think if we have this check then we don't need the the previous condition if (!/^https?:\/\//i.test(value)) cause i think both do the same check, right ?

@KhizerRehan
Copy link
Copy Markdown
Contributor

@SamuAlfageme thanks for the contribution!

Could you please review the feedback and let us know if anything is unclear? We’ve added a few comments for clarity and alignment.

If possible, please address the requested updates. Appreciate your effort.

@KhizerRehan
Copy link
Copy Markdown
Contributor

/hold
/retitle WIP: [UC Backup] BackupStorageLocation UX improvements

@kubermatic-bot kubermatic-bot changed the title [UC Backup] BackupStorageLocation UX improvements WIP: [UC Backup] BackupStorageLocation UX improvements Apr 23, 2026
@kubermatic-bot kubermatic-bot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. labels Apr 23, 2026
@SamuAlfageme
Copy link
Copy Markdown
Contributor Author

Hi @KhizerRehan, thank you for taking the time (together with @ahmadhamzh) to review this PR! I've been a bit busier than usual, but I should find some time to address your comments later this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Denotes that all commits in the pull request have the valid DCO signoff message. do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. do-not-merge/test-issue-needed Indicates that a PR should not merge because it's missing one of the test issue labels. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. docs/none Denotes a PR that doesn't need documentation (changes). kind/design Categorizes issue or PR as related to design. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants