Skip to content

Commit

Permalink
fix(website): don't expose the server side runtime config in details.…
Browse files Browse the repository at this point in the history
…json

The client side code only needs the client side config, which is already contained in the details.json anyway.
Also remove some lint ignores by introducing types for the details.json
  • Loading branch information
fengelniederhammer committed Jan 17, 2025
1 parent b2fbab3 commit ffee7ee
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 30 deletions.
12 changes: 6 additions & 6 deletions website/src/components/SearchPage/SeqPreviewModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Dialog, DialogPanel, Transition } from '@headlessui/react';
import React, { useEffect, useState } from 'react';

import { type DetailsJson, detailsJsonSchema } from '../../pages/seq/[accessionVersion]/details.json.ts';
import { routes } from '../../routes/routes';
import { type Group } from '../../types/backend';
import { type ReferenceGenomesSequenceNames } from '../../types/referencesGenomes';
Expand Down Expand Up @@ -28,7 +29,6 @@ interface SeqPreviewModalProps {
setPreviewedSeqId?: (seqId: string | null) => void;
}

/* eslint-disable @typescript-eslint/no-unsafe-member-access -- TODO(#3451) */
export const SeqPreviewModal: React.FC<SeqPreviewModalProps> = ({
seqId,
accessToken,
Expand All @@ -41,14 +41,15 @@ export const SeqPreviewModal: React.FC<SeqPreviewModalProps> = ({
setPreviewedSeqId,
}) => {
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState<any | null>(null); // eslint-disable-line @typescript-eslint/no-explicit-any -- TODO(#3451) use `unknown`or proper types
const [data, setData] = useState<DetailsJson | null>(null);
const [isError, setIsError] = useState(false);

useEffect(() => {
if (seqId) {
setIsLoading(true);
void fetch(`/seq/${seqId}/details.json`)
.then((res) => res.json())
.then((json) => detailsJsonSchema.parse(json))
.then(setData)
.catch(() => setIsError(true))
.finally(() => setIsLoading(false));
Expand All @@ -59,7 +60,7 @@ export const SeqPreviewModal: React.FC<SeqPreviewModalProps> = ({
<div
className={`mt-4 text-gray-700 overflow-y-auto ${isHalfScreen ? 'h-[calc(50vh-9rem)]' : 'h-[calc(100vh-9rem)]'}`}
>
{data !== null && data.isRevocation === true && (
{data !== null && data.isRevocation && (
<div className='bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative' role='alert'>
<strong className='font-bold'>This sequence has been revoked.</strong>
</div>
Expand All @@ -84,9 +85,9 @@ export const SeqPreviewModal: React.FC<SeqPreviewModalProps> = ({
<div className='flex justify-between items-center'>
<div className='text-xl font-medium leading-6 text-primary-700 pl-6'>{seqId}</div>
<div>
{data !== null && data?.sequenceEntryHistory !== undefined && data?.sequenceEntryHistory.length > 1 && (
{data !== null && data.sequenceEntryHistory.length > 1 && (
<SequenceEntryHistoryMenu
sequenceEntryHistory={data?.sequenceEntryHistory}
sequenceEntryHistory={data.sequenceEntryHistory}
accessionVersion={seqId}
setPreviewedSeqId={setPreviewedSeqId}
/>
Expand Down Expand Up @@ -135,7 +136,6 @@ export const SeqPreviewModal: React.FC<SeqPreviewModalProps> = ({
</Transition>
);
};
/* eslint-enable @typescript-eslint/no-unsafe-member-access */

interface DownloadButtonProps {
seqId: string;
Expand Down
6 changes: 2 additions & 4 deletions website/src/components/SequenceDetailsPage/SequenceDataUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { DATA_USE_TERMS_FIELD } from '../../settings.ts';
import { type DataUseTermsHistoryEntry, type Group, type RestrictedDataUseTerms } from '../../types/backend';
import { type Schema } from '../../types/config';
import { type ReferenceGenomesSequenceNames } from '../../types/referencesGenomes';
import { type ClientConfig, type RuntimeConfig } from '../../types/runtimeConfig';
import { type ClientConfig } from '../../types/runtimeConfig';
import { EditDataUseTermsButton } from '../DataUseTerms/EditDataUseTermsButton';
import ErrorBox from '../common/ErrorBox';
import MdiEye from '~icons/mdi/eye';
Expand All @@ -21,7 +21,6 @@ interface Props {
accessionVersion: string;
dataUseTermsHistory: DataUseTermsHistoryEntry[];
schema: Schema;
runtimeConfig: RuntimeConfig;
clientConfig: ClientConfig;
myGroups: Group[];
accessToken: string | undefined;
Expand All @@ -34,7 +33,6 @@ export const SequenceDataUI: FC<Props> = ({
accessionVersion,
dataUseTermsHistory,
schema,
runtimeConfig,
clientConfig,
myGroups,
accessToken,
Expand Down Expand Up @@ -74,7 +72,7 @@ export const SequenceDataUI: FC<Props> = ({
<SequencesContainer
organism={organism}
accessionVersion={accessionVersion}
clientConfig={runtimeConfig.public}
clientConfig={clientConfig}
genes={genes}
nucleotideSegmentNames={nucleotideSegmentNames}
loadSequencesAutomatically={loadSequencesAutomatically}
Expand Down
28 changes: 18 additions & 10 deletions website/src/components/SequenceDetailsPage/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import type { CustomDisplay, MetadataType } from '../../types/config.ts';
export type TableDataEntry = {
label: string;
name: string;
value: string | number | boolean;
header: string;
customDisplay?: CustomDisplay;
type: TableDataEntryType;
};
import { z } from 'zod';

export type TableDataEntryType = { kind: 'metadata'; metadataType: MetadataType } | { kind: 'mutation' };
import { customDisplay, metadataPossibleTypes } from '../../types/config.ts';

export const tableDataEntryTypeSchema = z.discriminatedUnion('kind', [
z.object({ kind: z.literal('metadata'), metadataType: metadataPossibleTypes }),
z.object({ kind: z.literal('mutation') }),
]);
export type TableDataEntryType = z.infer<typeof tableDataEntryTypeSchema>;

export const tableDataEntrySchema = z.object({
label: z.string(),
name: z.string(),
value: z.union([z.string(), z.number(), z.boolean()]),
header: z.string(),
customDisplay: customDisplay.optional(),
type: tableDataEntryTypeSchema,
});
export type TableDataEntry = z.infer<typeof tableDataEntrySchema>;
25 changes: 21 additions & 4 deletions website/src/pages/seq/[accessionVersion]/details.json.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
import { type APIRoute } from 'astro';
import { z } from 'zod';

import { findOrganismAndData } from './findOrganismAndData';
import { SequenceDetailsTableResultType } from './getSequenceDetailsTableData';
import { getSchema, getRuntimeConfig } from '../../../config';
import { tableDataEntrySchema } from '../../../components/SequenceDetailsPage/types.ts';
import { getRuntimeConfig, getSchema } from '../../../config';
import { dataUseTermsHistoryEntry } from '../../../types/backend.ts';
import { schema } from '../../../types/config.ts';
import { sequenceEntryHistory } from '../../../types/lapis.ts';
import { serviceUrls } from '../../../types/runtimeConfig.ts';

export const detailsJsonSchema = z.object({
tableData: z.array(tableDataEntrySchema),
organism: z.string(),
accessionVersion: z.string(),
dataUseTermsHistory: z.array(dataUseTermsHistoryEntry),
schema: schema,
clientConfig: serviceUrls,
isRevocation: z.boolean(),
sequenceEntryHistory: sequenceEntryHistory,
});

export type DetailsJson = z.infer<typeof detailsJsonSchema>;

export const GET: APIRoute = async (req) => {
const params = req.params as { accessionVersion: string; accessToken?: string };
Expand All @@ -26,15 +45,13 @@ export const GET: APIRoute = async (req) => {
const clientConfig = getRuntimeConfig().public;

const schema = getSchema(organism);
const runtimeConfig = getRuntimeConfig();

const detailsDataUIProps = {
const detailsDataUIProps: DetailsJson = {
tableData: result.tableData,
organism,
accessionVersion,
dataUseTermsHistory: result.dataUseTermsHistory,
schema,
runtimeConfig,
clientConfig,
isRevocation: result.isRevocation,
sequenceEntryHistory: result.sequenceEntryHistory,
Expand Down
3 changes: 0 additions & 3 deletions website/src/pages/seq/[accessionVersion]/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ let myGroups: Group[] = [];
if (accessToken !== undefined) {
myGroups = await getMyGroups(accessToken);
}
const runtimeConfig = getRuntimeConfig();
---

<BaseLayout
Expand Down Expand Up @@ -81,7 +79,6 @@ const runtimeConfig = getRuntimeConfig();
accessionVersion={accessionVersion}
dataUseTermsHistory={result.dataUseTermsHistory}
schema={getSchema(organism)}
runtimeConfig={runtimeConfig}
clientConfig={clientConfig}
myGroups={myGroups}
accessToken={accessToken}
Expand Down
12 changes: 10 additions & 2 deletions website/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@ import { mutationProportionCount, orderByType } from './lapis.ts';
import { referenceGenomes } from './referencesGenomes.ts';

// These metadata types need to be kept in sync with the backend config class `MetadataType` in Config.kt
const metadataPossibleTypes = z.enum(['string', 'date', 'int', 'float', 'timestamp', 'boolean', 'authors'] as const);
export const metadataPossibleTypes = z.enum([
'string',
'date',
'int',
'float',
'timestamp',
'boolean',
'authors',
] as const);

export const segmentedMutations = z.object({
segment: z.string(),
Expand Down Expand Up @@ -88,7 +96,7 @@ export type GroupedMetadataFilter = {
initiallyVisible?: boolean;
};

const schema = z.object({
export const schema = z.object({
organismName: z.string(),
image: z.string().optional(),
description: z.string().optional(),
Expand Down
2 changes: 1 addition & 1 deletion website/src/types/runtimeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { z } from 'zod';

export const name = z.string().min(1);

const serviceUrls = z.object({
export const serviceUrls = z.object({
backendUrl: z.string(),
lapisUrls: z.record(z.string(), z.string()),
});
Expand Down

0 comments on commit ffee7ee

Please sign in to comment.