Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions app/forms/silo-access.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import { Access16Icon } from '@oxide/design-system/icons/react'

import { ListboxField } from '~/components/form/fields/ListboxField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { useCurrentUser } from '~/hooks/use-current-user'
import { confirmAction } from '~/stores/confirm-action'
import { SideModalFormDocs } from '~/ui/lib/ModalLinks'
import { ResourceLabel } from '~/ui/lib/SideModal'
import { docLinks } from '~/util/links'
Expand Down Expand Up @@ -86,6 +89,7 @@ export function SiloAccessEditUserSideModal({
policy,
defaultValues,
}: EditRoleModalProps) {
const { me } = useCurrentUser()
const updatePolicy = useApiMutation(api.policyUpdate, {
onSuccess: () => {
queryClient.invalidateEndpoint('policyView')
Expand All @@ -106,9 +110,31 @@ export function SiloAccessEditUserSideModal({
</ResourceLabel>
}
onSubmit={({ roleName }) => {
updatePolicy.mutate({
body: updateRole({ identityId, identityType, roleName }, policy),
})
const body = updateRole({ identityId, identityType, roleName }, policy)
// Only silo admins can edit the policy, so an admin who removes their
// own admin role may not be able to undo the change. "May" because
// they could still be an admin through a group.
if (
identityId === me.id &&
defaultValues.roleName === 'admin' &&
roleName !== 'admin'
) {
confirmAction({
actionType: 'danger',
doAction: () => updatePolicy.mutateAsync({ body }),
modalTitle: 'Remove your own admin role',
modalContent: (
<p>
You are removing the <HL>admin</HL> role from your own account. You may lose
the ability to manage access to this silo, including restoring your own
role. Are you sure?
</p>
),
errorTitle: 'Could not update role',
})
return
}
updatePolicy.mutate({ body })
}}
loading={updatePolicy.isPending}
submitError={updatePolicy.error}
Expand Down
38 changes: 38 additions & 0 deletions test/e2e/silo-access.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,41 @@ test('Click through silo access page', async ({ page }) => {
await page.getByRole('button', { name: 'Confirm' }).click()
await expect(user3Row).toBeHidden()
})

// changing your own role away from admin requires confirmation because you
// may not be able to undo it
test('Removing your own admin role requires confirmation', async ({ page }) => {
await page.goto('/access')

const table = page.getByRole('table')

// Hannah Arendt is the mock session user and a silo admin
const openEditForm = async () => {
await page
.getByRole('row', { name: 'Hannah Arendt' })
.getByRole('button', { name: 'Row actions' })
.click()
await page.getByRole('menuitem', { name: 'Change role' }).click()
await page.getByRole('radio', { name: /^Viewer / }).click()
await page.getByRole('button', { name: 'Update role' }).click()
}
const editForm = page.getByRole('dialog', { name: 'Edit role' })
const confirmModal = page.getByRole('dialog', { name: 'Remove your own admin role' })

// confirmation modal pops up over the side modal. cancel out of it, then
// close the form and check nothing changed
await openEditForm()
await expect(confirmModal).toBeVisible()
await confirmModal.getByRole('button', { name: 'Cancel' }).click()
await expect(confirmModal).toBeHidden()
await expect(editForm).toBeVisible()
await editForm.getByRole('button', { name: 'Cancel' }).click()
await expectRowVisible(table, { Name: 'Hannah Arendt', Role: 'silo.admin' })

// this time, confirm
await openEditForm()
await confirmModal.getByRole('button', { name: 'Confirm' }).click()

await expect(editForm).toBeHidden()
await expectRowVisible(table, { Name: 'Hannah Arendt', Role: 'silo.viewer' })
})
Loading