Skip to content

Commit

Permalink
Move to operation
Browse files Browse the repository at this point in the history
  • Loading branch information
codyebberson committed May 14, 2024
1 parent a43e906 commit 89888be
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 38 deletions.
20 changes: 18 additions & 2 deletions packages/app/src/admin/SuperAdminPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Button, Divider, NativeSelect, PasswordInput, Stack, TextInput, Title } from '@mantine/core';
import { Button, Divider, Modal, NativeSelect, PasswordInput, Stack, TextInput, Title } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { notifications, showNotification } from '@mantine/notifications';
import { MedplumClient, MedplumRequestOptions, forbidden, normalizeErrorString } from '@medplum/core';
import { Parameters } from '@medplum/fhirtypes';
import {
DateTimeInput,
Document,
Expand All @@ -11,9 +13,13 @@ import {
useMedplum,
} from '@medplum/react';
import { IconCheck, IconX } from '@tabler/icons-react';
import { ReactNode, useState } from 'react';

export function SuperAdminPage(): JSX.Element {
const medplum = useMedplum();
const [opened, { open, close }] = useDisclosure(false);
const [modalTitle, setModalTitle] = useState('');
const [modalContent, setModalContent] = useState<ReactNode | undefined>();

if (!medplum.isLoading() && !medplum.isSuperAdmin()) {
return <OperationOutcomeAlert outcome={forbidden} />;
Expand Down Expand Up @@ -61,7 +67,14 @@ export function SuperAdminPage(): JSX.Element {
}

function getDatabaseStats(): void {
startAsyncJob(medplum, 'Get Database Stats', 'admin/super/dbstats', {});
medplum
.post('fhir/R4/$db-stats', {})
.then((params: Parameters) => {
setModalTitle('Database Stats');
setModalContent(<pre>{params.parameter?.find((p) => p.name === 'tableString')?.valueString}</pre>);
open();
})
.catch((err) => showNotification({ color: 'red', message: normalizeErrorString(err), autoClose: false }));
}

return (
Expand Down Expand Up @@ -169,6 +182,9 @@ export function SuperAdminPage(): JSX.Element {
<Form onSubmit={getDatabaseStats}>
<Button type="submit">Get Database Stats</Button>
</Form>
<Modal opened={opened} onClose={close} title={modalTitle} centered>
{modalContent}
</Modal>
</Document>
);
}
Expand Down
36 changes: 0 additions & 36 deletions packages/server/src/admin/super.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { rebuildR4SearchParameters } from '../seeds/searchparameters';
import { rebuildR4StructureDefinitions } from '../seeds/structuredefinitions';
import { rebuildR4ValueSets } from '../seeds/valuesets';
import { removeBullMQJobByKey } from '../workers/cron';
import { Communication } from '@medplum/fhirtypes';

export const superAdminRouter = Router();
superAdminRouter.use(authenticateRequest);
Expand Down Expand Up @@ -220,41 +219,6 @@ superAdminRouter.post(
})
);

// POST to /admin/super/dbstats
// to query database statistics.
superAdminRouter.post(
'/dbstats',
asyncWrap(async (req: Request, res: Response) => {
requireSuperAdmin();
requireAsync(req);

await sendAsyncResponse(req, res, async () => {
const systemRepo = getSystemRepo();
const client = getDatabasePool();
const sql = `
SELECT * FROM (
SELECT table_schema, table_name, pg_relation_size('"'||table_schema||'"."'||table_name||'"') AS table_size
FROM information_schema.tables
) tables
WHERE table_size > 0
ORDER BY table_size DESC;
`;

const result = await client.query(sql);

const contentString = result.rows
.map((row) => `${row.table_schema}.${row.table_name}: ${row.table_size}`)
.join('\n');

await systemRepo.createResource<Communication>({
resourceType: 'Communication',
status: 'completed',
payload: [{ contentString }],
});
});
})
);

export function requireSuperAdmin(): AuthenticatedRequestContext {
const ctx = getAuthenticatedContext();
if (!ctx.project.superAdmin) {
Expand Down
39 changes: 39 additions & 0 deletions packages/server/src/fhir/operations/dbstats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { allOk } from '@medplum/core';
import { FhirRequest, FhirResponse } from '@medplum/fhir-router';
import { OperationDefinition } from '@medplum/fhirtypes';
import { requireSuperAdmin } from '../../admin/super';
import { getDatabasePool } from '../../database';
import { buildOutputParameters } from './utils/parameters';

const operation: OperationDefinition = {
resourceType: 'OperationDefinition',
name: 'db-stats',
status: 'active',
kind: 'operation',
code: 'status',
experimental: true,
system: true,
type: false,
instance: false,
parameter: [{ use: 'out', name: 'tableString', type: 'string', min: 1, max: '1' }],
};

export async function dbStatsHandler(_req: FhirRequest): Promise<FhirResponse> {
requireSuperAdmin();

const client = getDatabasePool();
const sql = `
SELECT * FROM (
SELECT table_schema, table_name, pg_relation_size('"'||table_schema||'"."'||table_name||'"') AS table_size
FROM information_schema.tables
) tables
WHERE table_size > 0
ORDER BY table_size DESC;
`;

const result = await client.query(sql);

const tableString = result.rows.map((row) => `${row.table_schema}.${row.table_name}: ${row.table_size}`).join('\n');

return [allOk, buildOutputParameters(operation, { tableString })];
}
4 changes: 4 additions & 0 deletions packages/server/src/fhir/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { codeSystemLookupHandler } from './operations/codesystemlookup';
import { codeSystemValidateCodeHandler } from './operations/codesystemvalidatecode';
import { conceptMapTranslateHandler } from './operations/conceptmaptranslate';
import { csvHandler } from './operations/csv';
import { dbStatsHandler } from './operations/dbstats';
import { deployHandler } from './operations/deploy';
import { evaluateMeasureHandler } from './operations/evaluatemeasure';
import { executeHandler } from './operations/execute';
Expand Down Expand Up @@ -247,6 +248,9 @@ function initInternalFhirRouter(): FhirRouter {
return [allOk];
});

// Super admin operations
router.add('POST', '/$db-stats', dbStatsHandler);

router.addEventListener('warn', (e: any) => {
const ctx = getAuthenticatedContext();
ctx.logger.warn(e.message, { ...e.data, project: ctx.project.id });
Expand Down

0 comments on commit 89888be

Please sign in to comment.