-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(renterd): keys batch operations
- Loading branch information
1 parent
69c3652
commit 6b8ec55
Showing
23 changed files
with
360 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@siafoundation/e2e': minor | ||
--- | ||
|
||
Add getTextInputValueByName method. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'renterd': minor | ||
--- | ||
|
||
The key management table now supports multiselect and batch deletion. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'hostd': minor | ||
'renterd': minor | ||
--- | ||
|
||
The onboarding wizard is now bottom right aligned. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@siafoundation/e2e': minor | ||
--- | ||
|
||
Add toggleColumnVisibility view preferences method. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Page, expect } from '@playwright/test' | ||
import { navigateToKeys } from './navigate' | ||
import { getTextInputValueByName } from '@siafoundation/e2e' | ||
|
||
export function getKeyRowById(page: Page, id: string) { | ||
return page.getByTestId('keysTable').getByTestId(id) | ||
} | ||
|
||
export function getKeysSummaryRow(page: Page) { | ||
return page.getByTestId('keysTable').locator('thead').getByRole('row').nth(1) | ||
} | ||
|
||
export function getKeyRowByIndex(page: Page, index: number) { | ||
return page | ||
.getByTestId('keysTable') | ||
.locator('tbody') | ||
.getByRole('row') | ||
.nth(index) | ||
} | ||
|
||
export async function getKeyRows(page: Page) { | ||
return page.getByTestId('keysTable').locator('tbody').getByRole('row').all() | ||
} | ||
|
||
export async function createKey(page: Page): Promise<string> { | ||
await navigateToKeys({ page }) | ||
await page.getByTestId('navbar').getByText('Create keypair').click() | ||
const dialog = page.getByRole('dialog') | ||
const accessKeyId = await getTextInputValueByName(page, 'name') | ||
await dialog.getByRole('button', { name: 'Create' }).click() | ||
const row = getKeyRowById(page, accessKeyId) | ||
await expect(dialog).toBeHidden() | ||
await expect(row).toBeVisible() | ||
return accessKeyId | ||
} | ||
|
||
export async function openKeyContextMenu(page: Page, key: string) { | ||
const selector = page.getByTestId(key).getByLabel('key context menu') | ||
await expect(selector).toBeVisible() | ||
await selector.click() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { test, expect } from '@playwright/test' | ||
import { afterTest, beforeTest } from '../fixtures/beforeTest' | ||
import { | ||
createKey, | ||
getKeyRowById, | ||
getKeyRowByIndex, | ||
openKeyContextMenu, | ||
} from '../fixtures/keys' | ||
|
||
test.beforeEach(async ({ page }) => { | ||
await beforeTest(page) | ||
}) | ||
|
||
test.afterEach(async () => { | ||
await afterTest() | ||
}) | ||
|
||
test('create and delete a key', async ({ page }) => { | ||
const key = await createKey(page) | ||
const row = getKeyRowById(page, key) | ||
await openKeyContextMenu(page, key) | ||
await page.getByRole('menu').getByText('Delete').click() | ||
const dialog = page.getByRole('dialog') | ||
await dialog.getByRole('button', { name: 'Delete' }).click() | ||
await expect(row).toBeHidden() | ||
}) | ||
|
||
test('batch delete multiple keys', async ({ page }) => { | ||
// Create 3 keys. Note: 1 already exists. | ||
const key1 = await createKey(page) | ||
const key2 = await createKey(page) | ||
const key3 = await createKey(page) | ||
const row1 = getKeyRowById(page, key1) | ||
const row2 = getKeyRowById(page, key2) | ||
const row3 = getKeyRowById(page, key3) | ||
|
||
// There are 4 keys total. Get the first and last row. | ||
const rowIdx0 = getKeyRowByIndex(page, 0) | ||
const rowIdx3 = getKeyRowByIndex(page, 3) | ||
|
||
// Select all 4 keys. | ||
await rowIdx0.getByLabel('select key').click() | ||
await rowIdx3.getByLabel('select key').click({ modifiers: ['Shift'] }) | ||
|
||
// Delete all 4 keys. | ||
const menu = page.getByLabel('key multiselect menu') | ||
await menu.getByLabel('delete selected keys').click() | ||
const dialog = page.getByRole('dialog') | ||
await dialog.getByRole('button', { name: 'Delete' }).click() | ||
await expect(row1).toBeHidden() | ||
await expect(row2).toBeHidden() | ||
await expect(row3).toBeHidden() | ||
await expect( | ||
page.getByText('There are no S3 authentication keypairs yet.') | ||
).toBeVisible() | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
apps/renterd/components/Keys/KeysBatchMenu/KeysBatchDelete.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { | ||
Button, | ||
Paragraph, | ||
triggerSuccessToast, | ||
triggerErrorToast, | ||
} from '@siafoundation/design-system' | ||
import { Delete16 } from '@siafoundation/react-icons' | ||
import { | ||
useSettingsS3, | ||
useSettingsS3Update, | ||
} from '@siafoundation/renterd-react' | ||
import { useCallback, useMemo } from 'react' | ||
import { omit } from '@technically/lodash' | ||
import { useDialog } from '../../../contexts/dialog' | ||
import { useKeys } from '../../../contexts/keys' | ||
|
||
export function KeysBatchDelete() { | ||
const { selectionMap, deselect } = useKeys() | ||
|
||
const ids = useMemo( | ||
() => Object.entries(selectionMap).map(([_, item]) => item.id), | ||
[selectionMap] | ||
) | ||
const keys = useMemo( | ||
() => Object.entries(selectionMap).map(([_, item]) => item.key), | ||
[selectionMap] | ||
) | ||
const { openConfirmDialog } = useDialog() | ||
const settingsS3 = useSettingsS3() | ||
const settingsS3Update = useSettingsS3Update() | ||
const deleteKeys = useCallback(async () => { | ||
if (!settingsS3.data) { | ||
triggerErrorToast({ title: 'Error deleting key' }) | ||
return | ||
} | ||
const newKeys = omit(settingsS3.data?.authentication.v4Keypairs, keys) | ||
const response = await settingsS3Update.put({ | ||
payload: { | ||
...settingsS3.data, | ||
authentication: { | ||
...settingsS3.data.authentication, | ||
v4Keypairs: newKeys, | ||
}, | ||
}, | ||
}) | ||
deselect(ids) | ||
if (response.error) { | ||
triggerErrorToast({ title: 'Error deleting keys', body: response.error }) | ||
} else { | ||
triggerSuccessToast({ title: `Keys deleted` }) | ||
} | ||
}, [settingsS3.data, settingsS3Update, deselect, keys, ids]) | ||
|
||
return ( | ||
<Button | ||
aria-label="delete selected keys" | ||
tip="Delete selected keys" | ||
onClick={() => { | ||
openConfirmDialog({ | ||
title: `Delete keys`, | ||
action: 'Delete', | ||
variant: 'red', | ||
body: ( | ||
<div className="flex flex-col gap-1"> | ||
<Paragraph size="14"> | ||
Are you sure you would like to delete the{' '} | ||
{ids.length.toLocaleString()} selected keys? | ||
</Paragraph> | ||
</div> | ||
), | ||
onConfirm: async () => { | ||
deleteKeys() | ||
}, | ||
}) | ||
}} | ||
> | ||
<Delete16 /> | ||
</Button> | ||
) | ||
} |
Oops, something went wrong.