Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(backend/frontend): 3256 able to view deleted tenant #3299

Merged
merged 4 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
11 changes: 6 additions & 5 deletions packages/backend/src/tenants/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ describe('Tenant Service', (): void => {
expect(tenant).toEqual(createdTenant)
})

test('returns undefined if tenant is deleted', async (): Promise<void> => {
test('returns deletedAt set if tenant is deleted', async (): Promise<void> => {
const dbTenant = await Tenant.query(knex).insertAndFetch({
apiSecret: 'test-secret',
email: faker.internet.email(),
Expand All @@ -85,10 +85,10 @@ describe('Tenant Service', (): void => {
})

const tenant = await tenantService.get(dbTenant.id)
expect(tenant).toBeUndefined()
expect(tenant?.deletedAt).toBeDefined()
})

test('returns undefined if tenant is deleted', async (): Promise<void> => {
test('returns deletedAt set if tenant is deleted', async (): Promise<void> => {
const dbTenant = await Tenant.query(knex).insertAndFetch({
apiSecret: 'test-secret',
email: faker.internet.email(),
Expand All @@ -98,7 +98,7 @@ describe('Tenant Service', (): void => {
})

const tenant = await tenantService.get(dbTenant.id)
expect(tenant).toBeUndefined()
expect(tenant?.deletedAt).toBeDefined()
})
})

Expand Down Expand Up @@ -409,7 +409,8 @@ describe('Tenant Service', (): void => {
.mockImplementation(async () => undefined)
await tenantService.delete(tenant.id)

await expect(tenantService.get(tenant.id)).resolves.toBeUndefined()
const tenantDeleted = await tenantService.get(tenant.id)
await expect(tenantDeleted?.deletedAt).toBeDefined()

// Ensure that cache was set for deletion
expect(spyCacheDelete).toHaveBeenCalledTimes(1)
Expand Down
4 changes: 1 addition & 3 deletions packages/backend/src/tenants/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ async function getTenant(
): Promise<Tenant | undefined> {
const inMem = await deps.tenantCache.get(id)
if (inMem) return inMem
const tenant = await Tenant.query(deps.knex)
.findById(id)
.whereNull('deletedAt')
const tenant = await Tenant.query(deps.knex).findById(id)
if (tenant) await deps.tenantCache.set(tenant.id, tenant)

return tenant
Expand Down
51 changes: 31 additions & 20 deletions packages/frontend/app/routes/tenants.$tenantId.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
if (!tenant)
throw json(null, { status: 404, statusText: 'Tenant not found.' })

const tenantDeleted = tenant.deletedAt ? tenant.deletedAt.length > 0 : false
const me = await whoAmI(request)
return json({ tenant, me })
return json({ tenant, me, tenantDeleted })
}

export default function ViewTenantPage() {
const { tenant, me } = useLoaderData<typeof loader>()
const { tenant, me, tenantDeleted } = useLoaderData<typeof loader>()
const response = useActionData<typeof action>()
const navigation = useNavigation()
const [formData, setFormData] = useState<FormData>()
Expand Down Expand Up @@ -78,7 +79,9 @@ export default function ViewTenantPage() {
<div className='col-span-1 pt-3'>
<h3 className='text-lg font-medium'>General Information</h3>
<p className='text-sm'>
Created at {new Date(tenant.createdAt).toLocaleString()}
{tenantDeleted && tenant.deletedAt
? `Deleted at ${new Date(tenant.deletedAt).toLocaleString()}`
: `Created at ${new Date(tenant.createdAt).toLocaleString()}`}
</p>
<ErrorPanel errors={response?.errors.message} />
</div>
Expand All @@ -102,25 +105,29 @@ export default function ViewTenantPage() {
<Input
label='Public Name'
name='publicName'
disabled={tenantDeleted}
defaultValue={tenant.publicName ?? undefined}
error={response?.errors?.fieldErrors.publicName}
/>
<Input
label='Email'
name='email'
disabled={tenantDeleted}
defaultValue={tenant.email ?? undefined}
error={response?.errors?.fieldErrors.email}
/>
</div>
<div className='flex justify-end p-4'>
<Button
aria-label='save general information'
type='submit'
name='intent'
value='general'
>
{isSubmitting ? 'Saving ...' : 'Save'}
</Button>
{!tenantDeleted && (
<Button
aria-label='save general information'
type='submit'
name='intent'
value='general'
>
{isSubmitting ? 'Saving ...' : 'Save'}
</Button>
)}
</div>
</fieldset>
</Form>
Expand All @@ -147,25 +154,29 @@ export default function ViewTenantPage() {
<Input
name='idpConsentUrl'
label='Consent URL'
disabled={tenantDeleted}
defaultValue={tenant.idpConsentUrl ?? undefined}
error={response?.errors?.fieldErrors.idpConsentUrl}
/>
<PasswordInput
name='idpSecret'
label='Secret'
disabled={tenantDeleted}
defaultValue={tenant.idpSecret ?? undefined}
error={response?.errors?.fieldErrors.idpSecret}
/>
</div>
<div className='flex justify-end p-4'>
<Button
aria-label='save ip information'
type='submit'
name='intent'
value='ip'
>
{isSubmitting ? 'Saving ...' : 'Save'}
</Button>
{!tenantDeleted && (
<Button
aria-label='save ip information'
type='submit'
name='intent'
value='ip'
>
{isSubmitting ? 'Saving ...' : 'Save'}
</Button>
)}
</div>
</fieldset>
</Form>
Expand Down Expand Up @@ -197,7 +208,7 @@ export default function ViewTenantPage() {
</div>
{/* Sensitive - END */}
{/* DELETE TENANT - Danger zone */}
{me.isOperator && me.id !== tenant.id && (
{!tenantDeleted && me.isOperator && me.id !== tenant.id && (
<DangerZone title='Delete Tenant'>
<Form method='post' onSubmit={submitHandler}>
<Input type='hidden' name='id' value={tenant.id} />
Expand Down
8 changes: 2 additions & 6 deletions packages/frontend/app/routes/tenants._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,8 @@ export default function TenantsPage() {
tenantEdges.map((tenant) => (
<Table.Row
key={tenant.node.id}
className={tenant.node.deletedAt ? '' : 'cursor-pointer'}
onClick={() =>
tenant.node.deletedAt
? 'return'
: navigate(`/tenants/${tenant.node.id}`)
}
className='cursor-pointer'
onClick={() => navigate(`/tenants/${tenant.node.id}`)}
>
<Table.Cell>
<div className='flex flex-col'>
Expand Down
Loading