feat: redesign OIDC client details page

This commit is contained in:
Elias Schneider
2026-10-01 19:48:57 +02:00
parent 642ccc80d3
commit e588e3fc5d
22 changed files with 1058 additions and 787 deletions
+3 -3
View File
@@ -105,8 +105,8 @@ test('Grant a client user-delegated and client access to API permissions', async
// Nextcloud has no API access granted by default
await page.goto(`/settings/admin/oidc-clients/${oidcClients.nextcloud.id}`);
// Open the API access tab, where no API is listed yet, and add the Orders API
await page.getByRole('tab', { name: 'API access' }).click();
// Open the Access tab, where no API is listed yet, and add the Orders API
await page.getByRole('tab', { name: 'Access', exact: true }).click();
await expect(
page.getByText('This client has not been granted access to any API yet.')
).toBeVisible();
@@ -180,7 +180,7 @@ test('Grant a client access from the API details page', async ({ page }) => {
// The same grant shows up on the client's side of the relation
await page.goto(`/settings/admin/oidc-clients/${oidcClients.nextcloud.id}`);
await page.getByRole('tab', { name: 'API access' }).click();
await page.getByRole('tab', { name: 'Access', exact: true }).click();
await expect(page.getByRole('row', { name: apis.orders.name })).toContainText('1 / 2');
});
@@ -109,11 +109,9 @@ test('Saving a logout URL and revoking an app sends a verifiable logout token',
const client = oidcClients.nextcloud;
const logoutURL = `${receiver.url}/logout?tenant=test`;
await page.goto(`/settings/admin/oidc-clients/${client.id}`);
await page.getByRole('button', { name: 'Show Advanced Options' }).click();
await page.getByLabel('Back-Channel Logout URL', { exact: true }).fill(logoutURL);
await saveUnsavedChanges(page);
await page.reload();
await page.getByRole('button', { name: 'Show Advanced Options' }).click();
await expect(page.getByLabel('Back-Channel Logout URL', { exact: true })).toHaveValue(logoutURL);
await page.goto('/settings/apps');
+7 -24
View File
@@ -14,38 +14,26 @@ test.describe('Create OIDC client', () => {
await page.getByRole('button', { name: 'Add OIDC Client' }).click();
await page.getByLabel('Name').fill(oidcClient.name);
await page.getByLabel('Description').fill(oidcClient.description);
await page.getByLabel('Client Launch URL').fill(oidcClient.launchURL);
await page.getByRole('button', { name: 'Add' }).first().click();
await page.getByRole('button', { name: 'Add callback URL' }).click();
await page.getByTestId('callback-url-1').fill(oidcClient.callbackUrl);
await page.getByRole('button', { name: 'Add another' }).click();
await page.getByRole('button', { name: 'Add callback URL' }).click();
await page.getByTestId('callback-url-2').fill(oidcClient.secondCallbackUrl);
await page.locator('[role="tab"][data-value="light-logo"]').first().click();
await page.setInputFiles('#oidc-client-logo-light', 'resources/images/pingvin-share-logo.png');
await page.locator('[role="tab"][data-value="dark-logo"]').first().click();
await page.setInputFiles('#oidc-client-logo-dark', 'resources/images/pingvin-share-logo.png');
if (clientId) {
await page.getByRole('button', { name: 'Show Advanced Options' }).click();
await page.getByRole('button', { name: 'Set custom client ID' }).click();
await page.getByLabel('Client ID').fill(clientId);
}
await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('button', { name: 'Create', exact: true }).click();
await expect(page.locator('[data-type="success"]')).toHaveText(
'OIDC client created successfully'
);
const resolvedClientId = (await page.getByTestId('client-id').innerText()).trim();
const createdSecret = (
await page
.getByRole('tabpanel', { name: 'General', exact: true })
.getByTestId('client-secret')
.innerText()
).trim();
const createdSecret = (await page.getByTestId('created-client-secret').innerText()).trim();
expect(createdSecret).toMatch(/^\w{32}$/);
if (clientId) {
@@ -55,13 +43,8 @@ test.describe('Create OIDC client', () => {
}
await expect(page.getByLabel('Name')).toHaveValue(oidcClient.name);
await expect(page.getByLabel('Description')).toHaveValue(oidcClient.description);
await expect(page.getByTestId('callback-url-1')).toHaveValue(oidcClient.callbackUrl);
await expect(page.getByTestId('callback-url-2')).toHaveValue(oidcClient.secondCallbackUrl);
await expect(page.getByRole('img', { name: `${oidcClient.name} logo` }).first()).toBeVisible();
const res = await page.request.get(`/api/oidc/clients/${resolvedClientId}/logo`);
expect(res.ok()).toBeTruthy();
// The generated value is available on the creation page and is forgotten after a reload
await page.reload();
@@ -495,9 +478,9 @@ test('Filter OIDC clients by PAR requirement', async ({ page, request }) => {
test('Update OIDC client allowed user groups', async ({ page }) => {
await page.goto(`/settings/admin/oidc-clients/${oidcClients.nextcloud.id}`);
await page.getByRole('tab', { name: 'Allowed user groups' }).click();
await page.getByRole('tab', { name: 'Access', exact: true }).click();
await page.getByRole('button', { name: 'Restrict' }).click();
await page.getByRole('radio', { name: 'Selected user groups' }).click();
await page.getByRole('row', { name: userGroups.designers.name }).getByRole('checkbox').click();
await page.getByRole('row', { name: userGroups.developers.name }).getByRole('checkbox').click();
-3
View File
@@ -1576,8 +1576,6 @@ test.describe('Pushed Authorization Requests (PAR)', () => {
test('Admin UI: PAR toggle persists after save', async ({ page }) => {
await page.goto(`/settings/admin/oidc-clients/${client.id}`);
await page.getByRole('button', { name: 'Show Advanced Options' }).click();
// Enable the PAR toggle
const parToggle = page.getByRole('switch', { name: 'Requires Pushed Authorization' });
if (!(await parToggle.isChecked())) {
@@ -1587,7 +1585,6 @@ test.describe('Pushed Authorization Requests (PAR)', () => {
await saveUnsavedChanges(page);
await page.reload();
await page.getByRole('button', { name: 'Show Advanced Options' }).click();
const savedToggle = page.getByRole('switch', { name: 'Requires Pushed Authorization' });
await expect(savedToggle).toBeChecked();
});
+4 -4
View File
@@ -129,7 +129,7 @@ test.describe('SCIM Sync', () => {
test('Remove allowed group and sync', async ({ page }) => {
await syncScimServiceProvider(page);
await page.getByRole('tab', { name: 'Allowed user groups' }).click();
await page.getByRole('tab', { name: 'Access', exact: true }).click();
const developersCheckbox = page
.getByRole('row', { name: userGroups.developers.name })
@@ -155,10 +155,10 @@ test.describe('SCIM Sync', () => {
test('Remove group restrictions and sync', async ({ page }) => {
await syncScimServiceProvider(page);
await page.getByRole('tab', { name: 'Allowed user groups' }).click();
await page.getByRole('tab', { name: 'Access', exact: true }).click();
await page.getByRole('button', { name: 'Unrestrict' }).click();
await page.getByRole('button', { name: 'Unrestrict' }).nth(1).click();
await page.getByRole('radio', { name: 'All users' }).click();
await page.getByRole('alertdialog').getByRole('button', { name: 'Unrestrict' }).click();
await expect(
page.getByText('User groups restriction updated successfully', { exact: true })
).toBeVisible();