Skip to content

Commit

Permalink
Merge pull request #13437 from torchiaf/13402-wizard-steps
Browse files Browse the repository at this point in the history
Fleet GitRepo wizard UX improvements, new steps, fields size and banners
  • Loading branch information
torchiaf authored Feb 27, 2025
2 parents 3665e77 + be8f609 commit dc34dcc
Show file tree
Hide file tree
Showing 14 changed files with 387 additions and 279 deletions.
4 changes: 3 additions & 1 deletion cypress/e2e/blueprints/fleet/gitrepos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export const gitRepoCreateRequest = {
],
insecureSkipTLSVerify: false,
helmRepoURLRegex: 'https://charts.rancher.io/*',
helmSecretName: 'auth-95j88'
helmSecretName: '',
clientSecretName: '',
pollingInterval: '13'
}
};

Expand Down
20 changes: 17 additions & 3 deletions cypress/e2e/po/components/select-or-create-auth.po.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import LabeledSelectPo from '@/cypress/e2e/po/components/labeled-select.po';
import ComponentPo from '@/cypress/e2e/po/components/component.po';
import LabeledInputPo from '@/cypress/e2e/po/components/labeled-input.po';
import KnownHostsEditDialog from '@/cypress/e2e/po/prompts/KnownHostsEditDialog.po';

export default class SelectOrCreateAuthPo extends ComponentPo {
authSelect() {
Expand All @@ -11,6 +12,10 @@ export default class SelectOrCreateAuthPo extends ComponentPo {
return this.self().get(`${ this.selector } i.icon-spinner`);
}

openKnowHostsEditDialog() {
return this.self().find('[data-testid="input-known-ssh-hosts_open-dialog"]').click({ force: true });
}

setBasicAuthSecret(username: string, password: string) {
const usernameInput = new LabeledInputPo(`${ this.selector } [data-testid="auth-secret-basic-username"]`, this.self());
const passwordInput = new LabeledInputPo(`${ this.selector } [data-testid="auth-secret-basic-password"]`, this.self());
Expand All @@ -19,12 +24,21 @@ export default class SelectOrCreateAuthPo extends ComponentPo {
passwordInput.set(password);
}

setSSHSecret(privateKey: string, publicKey: string) {
setSSHSecret(privateKey: string, publicKey: string, knownHosts?: string) {
const privateKeyInput = new LabeledInputPo(`${ this.selector } [data-testid="auth-secret-ssh-private-key"]`, this.self());
const publicKeyInput = new LabeledInputPo(`${ this.selector } [data-testid="auth-secret-ssh-public-key"]`, this.self());

privateKeyInput.set(privateKey);
publicKeyInput.set(publicKey);

if (knownHosts) {
this.openKnowHostsEditDialog();

const knownHostsEditDialog = new KnownHostsEditDialog();

knownHostsEditDialog.set(knownHosts);
knownHostsEditDialog.save();
}
}

createBasicAuth(username = 'auth-test-user', password = 'auth-test-password') {
Expand All @@ -33,10 +47,10 @@ export default class SelectOrCreateAuthPo extends ComponentPo {
this.setBasicAuthSecret(username, password);
}

createSSHAuth(privateKey: string, publicKey: string) {
createSSHAuth(privateKey: string, publicKey: string, knownHosts?: string) {
this.authSelect().toggle();
this.authSelect().clickOptionWithLabel('Create an SSH Key Secret');
this.setSSHSecret(privateKey, publicKey);
this.setSSHSecret(privateKey, publicKey, knownHosts);
}

createRKEAuth(username = 'auth-test-user', password = 'auth-test-password') {
Expand Down
8 changes: 8 additions & 0 deletions cypress/e2e/po/pages/fleet/gitrepo-create.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,17 @@ export class GitRepoCreatePo extends PagePo {
}

helmAuthSelectOrCreate() {
return this.authSelectOrCreate('[data-testid="gitrepo-git-auth"]');
}

gitAuthSelectOrCreate() {
return this.authSelectOrCreate('[data-testid="gitrepo-helm-auth"]');
}

setPollingInterval(value: number) {
return LabeledInputPo.byLabel(this.self(), 'Polling Interval').set(value);
}

title() {
return this.self().get('.title .primaryheader h1');
}
Expand Down
15 changes: 15 additions & 0 deletions cypress/e2e/po/prompts/KnownHostsEditDialog.po.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import ComponentPo from '@/cypress/e2e/po/components/component.po';

export default class KnownHostsEditDialogPo extends ComponentPo {
constructor() {
super(cy.getId('sshKnownHostsDialog'));
}

set(value: string): Cypress.Chainable {
return this.self().get('[data-testid="ssh-known-hosts-dialog_code-mirror"]').type(value);
}

save() {
return this.self().get('[data-testid="ssh-known-hosts-dialog_save-btn"]').click({ force: true });
}
}
180 changes: 100 additions & 80 deletions cypress/e2e/tests/pages/fleet/gitrepo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,104 +57,124 @@ describe('Git Repo', { testIsolation: 'off', tags: ['@fleet', '@adminUser'] }, (

gitRepoCreatePage.goTo();
gitRepoCreatePage.waitForPage();
cy.wait('@getSecrets', EXTRA_LONG_TIMEOUT_OPT).its('response.statusCode').should('eq', 200);

const { name } = gitRepoCreateRequest.metadata;
const {
repo, branch, paths, helmRepoURLRegex
} = gitRepoCreateRequest.spec;

headerPo.selectWorkspace('fleet-default');

// Metadata step
gitRepoCreatePage.setRepoName(name);

gitRepoCreatePage.goToNext();

// Repository details step
gitRepoCreatePage.setGitRepoUrl(repo);
headerPo.selectWorkspace('fleet-default');
gitRepoCreatePage.setBranchName(branch);
gitRepoCreatePage.helmAuthSelectOrCreate().createBasicAuth('test', 'test');
gitRepoCreatePage.setHelmRepoURLRegex(helmRepoURLRegex);

gitRepoCreatePage.gitRepoPaths().setValueAtIndex(paths[0], 0);

gitRepoCreatePage.goToNext();

// Target info step
gitRepoCreatePage.targetCluster().toggle();
gitRepoCreatePage.targetCluster().clickOption(6);

gitRepoCreatePage.goToNext();

// Advanced info step
gitRepoCreatePage.gitAuthSelectOrCreate().createSSHAuth('test1', 'test1', 'KNOWN_HOSTS');
gitRepoCreatePage.helmAuthSelectOrCreate().createBasicAuth('test', 'test');
gitRepoCreatePage.setHelmRepoURLRegex(helmRepoURLRegex);
gitRepoCreatePage.setPollingInterval(13);

cy.wait('@getSecrets', EXTRA_LONG_TIMEOUT_OPT).its('response.statusCode').should('eq', 200);

gitRepoCreatePage.create().then(() => {
reposToDelete.push(`fleet-default/${ name }`);
});

// First request is for creating credentials
let secretName = '';
let requestLabels = null;
let secretLabels = null;

cy.wait('@interceptSecret')
.then(({ request, response }) => {
requestLabels = request.body.metadata.labels;
expect(requestLabels).to.be.an('object').and.to.have.property('fleet.cattle.io/managed').that.equals('true');
expect(response.statusCode).to.eq(201);
secretName = response.body.metadata.name;
secretLabels = response.body.metadata.labels;
expect(secretName).not.to.eq('');
expect(secretLabels).to.be.an('object').and.to.have.property('fleet.cattle.io/managed').that.equals('true');

// Second request is for creating the git repo
return cy.wait('@interceptGitRepo');
})
.then(({ request, response }) => {
gitRepoCreateRequest.metadata.labels['fleet.cattle.io/created-by-display-name'] = adminUsername;
gitRepoCreateRequest.metadata.labels['fleet.cattle.io/created-by-user-id'] = adminUserId;
gitRepoCreateRequest.spec.helmSecretName = secretName;

expect(response.statusCode).to.eq(201);
expect(request.body).to.deep.eq(gitRepoCreateRequest);

const listPage = new FleetGitRepoListPagePo();

listPage.waitForPage();

const prefPage = new PreferencesPagePo();

// START TESTING https://github.com/rancher/dashboard/issues/9984
// change language to chinese
prefPage.goTo();
prefPage.languageDropdownMenu().checkVisible();
prefPage.languageDropdownMenu().toggle();
prefPage.languageDropdownMenu().isOpened();

cy.intercept({
method: 'PUT', url: 'v1/userpreferences/*', times: 1
}).as(`prefUpdateZhHans`);
prefPage.languageDropdownMenu().clickOption(2);
cy.wait('@prefUpdateZhHans').then(({ response }) => {
expect(response?.statusCode).to.eq(200);
expect(response?.body.data).to.have.property('locale', 'zh-hans');
});
prefPage.languageDropdownMenu().isClosed();

listPage.goTo();
listPage.waitForPage();
listPage.repoList().resourceTable().checkVisible();
listPage.repoList().resourceTable().sortableTable().checkVisible();
listPage.repoList().resourceTable().sortableTable().checkLoadingIndicatorNotVisible();
listPage.repoList().resourceTable().sortableTable().noRowsShouldNotExist();

// TESTING https://github.com/rancher/dashboard/issues/9984 make sure details page loads fine
listPage.goToDetailsPage('fleet-e2e-test-gitrepo');
gitRepoCreatePage.title().contains('Git 仓库: fleet-e2e-test-gitrepo').should('be.visible');

// https://github.com/rancher/dashboard/issues/9984 reset lang to EN so that delete action can be performed
prefPage.goTo();
prefPage.languageDropdownMenu().checkVisible();
prefPage.languageDropdownMenu().toggle();
prefPage.languageDropdownMenu().isOpened();

cy.intercept('PUT', 'v1/userpreferences/*').as(`prefUpdateEnUs`);
prefPage.languageDropdownMenu().clickOptionWithLabel('English');
cy.wait('@prefUpdateEnUs').then(({ response }) => {
expect(response?.statusCode).to.eq(200);
expect(response?.body.data).to.have.property('locale', 'en-us'); // Flake: This can sometimes be zh-hans.....?!
});
prefPage.languageDropdownMenu().isClosed();
})
;
let gitSecretName = '';
let helmSecretName = '';

// Intercept 2nd interceptSecret call - Git SSH secret creation, see https://docs.cypress.io/api/commands/intercept#Interception-lifecycle
cy.wait('@interceptSecret').then(({ request, response }) => {
gitSecretName = response.body.metadata.name;

expect(request.body.metadata.labels).to.be.an('object').and.to.have.property('fleet.cattle.io/managed').that.equals('true');
expect(response.statusCode).to.eq(201);
expect(gitSecretName).not.to.eq('');
expect(response.body.metadata.labels).to.be.an('object').and.to.have.property('fleet.cattle.io/managed').that.equals('true');
});

// Intercept 1st interceptSecret call - Helm secret creation see https://docs.cypress.io/api/commands/intercept#Interception-lifecycle
cy.wait('@interceptSecret').then(({ request, response }) => {
helmSecretName = response.body.metadata.name;

expect(request.body.metadata.labels).to.be.an('object').and.to.have.property('fleet.cattle.io/managed').that.equals('true');
expect(response.statusCode).to.eq(201);
expect(helmSecretName).not.to.eq('');
expect(response.body.metadata.labels).to.be.an('object').and.to.have.property('fleet.cattle.io/managed').that.equals('true');
});

cy.wait('@interceptGitRepo').then(({ request, response }) => {
gitRepoCreateRequest.metadata.labels['fleet.cattle.io/created-by-display-name'] = adminUsername;
gitRepoCreateRequest.metadata.labels['fleet.cattle.io/created-by-user-id'] = adminUserId;
gitRepoCreateRequest.spec.helmSecretName = helmSecretName;
gitRepoCreateRequest.spec.clientSecretName = gitSecretName; // Git SSH credentials

expect(response.statusCode).to.eq(201);
expect(request.body).to.deep.eq(gitRepoCreateRequest);

const listPage = new FleetGitRepoListPagePo();

listPage.waitForPage();

const prefPage = new PreferencesPagePo();

// START TESTING https://github.com/rancher/dashboard/issues/9984
// change language to chinese
prefPage.goTo();
prefPage.languageDropdownMenu().checkVisible();
prefPage.languageDropdownMenu().toggle();
prefPage.languageDropdownMenu().isOpened();

cy.intercept({
method: 'PUT', url: 'v1/userpreferences/*', times: 1
}).as(`prefUpdateZhHans`);
prefPage.languageDropdownMenu().clickOption(2);
cy.wait('@prefUpdateZhHans').then(({ response }) => {
expect(response?.statusCode).to.eq(200);
expect(response?.body.data).to.have.property('locale', 'zh-hans');
});
prefPage.languageDropdownMenu().isClosed();

listPage.goTo();
listPage.waitForPage();
listPage.repoList().resourceTable().checkVisible();
listPage.repoList().resourceTable().sortableTable().checkVisible();
listPage.repoList().resourceTable().sortableTable().checkLoadingIndicatorNotVisible();
listPage.repoList().resourceTable().sortableTable().noRowsShouldNotExist();

// TESTING https://github.com/rancher/dashboard/issues/9984 make sure details page loads fine
listPage.goToDetailsPage('fleet-e2e-test-gitrepo');
gitRepoCreatePage.title().contains('Git 仓库: fleet-e2e-test-gitrepo').should('be.visible');

// https://github.com/rancher/dashboard/issues/9984 reset lang to EN so that delete action can be performed
prefPage.goTo();
prefPage.languageDropdownMenu().checkVisible();
prefPage.languageDropdownMenu().toggle();
prefPage.languageDropdownMenu().isOpened();

cy.intercept('PUT', 'v1/userpreferences/*').as(`prefUpdateEnUs`);
prefPage.languageDropdownMenu().clickOptionWithLabel('English');
cy.wait('@prefUpdateEnUs').then(({ response }) => {
expect(response?.statusCode).to.eq(200);
expect(response?.body.data).to.have.property('locale', 'en-us'); // Flake: This can sometimes be zh-hans.....?!
});
prefPage.languageDropdownMenu().isClosed();
});
});

it('check table headers are available in list and details view', { tags: ['@vai', '@adminUser'] }, function() {
Expand Down
26 changes: 18 additions & 8 deletions shell/assets/translations/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2462,7 +2462,6 @@ fleet:
notReady: Not Ready
waitApplied: Wait Applied
gitRepo:
createLocalBanner: When deploying a Git Repo to the Local workspace you are unable to target any specific Cluster or Cluster Groups
actions:
forceUpdate:
label: Force Update
Expand Down Expand Up @@ -2507,27 +2506,38 @@ fleet:
noWorkspaces: There are no workspaces. <br/> Please create a workspace before adding repositories
resources:
label: 'Resource Handling'
keepResources: Always Keep Resources
keepResources: Always keep resources
keepResourcesTooltip: When enabled, resources will be kept when deleting a GitRepo or Bundle - only Helm release secrets will be deleted.
correctDrift: Enable Self-Healing
correctDrift: Enable self-healing
correctDriftTooltip: When enabled, Fleet will ensure that the cluster resources are kept in sync with the git repository. All resource changes made on the cluster will be lost.
polling:
label: Polling
enable: Enable Polling
pollingInterval:
label: Polling Interval
tooltip: Polling Interval is the time between a push to the Repository and Fleet's reaction to it.
webhookWarning: Warning, a webhook is configured in Rancher to reconcile Git updates and GitRepo resources. The Polling Interval will automatically be adjusted to 1 hour.
minimumValuewarning: Warning, the recommended minimum Polling Interval is 15 seconds. To avoid performance issues with GitRepos that contain a large amount of resources please consider increasing this value.
webhookWarning: A webhook is configured in Rancher to reconcile Git updates and GitRepo resources. The Polling Interval will automatically be adjusted to 1 hour.
minimumValuewarning: The recommended minimum Polling Interval is 15 seconds. To avoid performance issues with GitRepos that contain a large amount of resources please consider increasing this value.
add:
steps:
repoInfo:
label: Repository Details
metadata:
label: Metadata
title: Specify the Git Repository name and labels/annotations
subtext: 'Define metadata details'
description: Git repository basic info
repo:
label: Repository details
title: Specify the Git Repository to add to fleet
subtext: 'Define repository details'
description: Fleet will continuously monitor the Git Repository you configure below and synchronise the resources contained in it to the configured targets.
advanced:
label: Advanced
title: Specify advanced settings like authenticaion credentials and polling
subtext: 'Define advanced settings'
description: Fleet will use the authentication settings and polling to synchronise the resources contained in it.
info: These settings are for advanced usage and optional. You can skip them and finish the creation process.
targetInfo:
label: Target Details
label: Target details
title: Specify which target to synchronise this repository to
subtext: 'Define target details'
description: You can configure which clusters will be used as the target of synchronisation with the resources in the repository.
Expand Down
1 change: 0 additions & 1 deletion shell/assets/translations/zh-hans.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2131,7 +2131,6 @@ fleet:
notReady: 未就绪
waitApplied: 等待应用
gitRepo:
createLocalBanner: 将 Git 仓库部署到本地工作区时,你无法定位任何集群或集群组
tabs:
resources: 资源
unready: 未就绪
Expand Down
Loading

0 comments on commit dc34dcc

Please sign in to comment.