Skip to content

Commit

Permalink
feat(website): Group metadata fields on the revision page (#3651)
Browse files Browse the repository at this point in the history
* .

* drill through groupedInputFields

* Add headers

* remove unused prop

* Don't show empty sections

* Test fix

* Theos input
  • Loading branch information
fhennig authored Feb 10, 2025
1 parent e79c63a commit ec43406
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 60 deletions.
2 changes: 1 addition & 1 deletion website/src/components/Edit/DataRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const EditableDataRow: FC<EditableRowProps> = ({ label, inputField, row,
<tr className='table-fixed w-full'>
<div>
<td className={`w-1/4 relative ${colorClassName}`} data-tooltip-id={'field-tooltip' + row.key}>
{label ?? row.key}:
{`${label ?? row.key}:`}
</td>
<Tooltip
id={'field-tooltip' + row.key}
Expand Down
33 changes: 23 additions & 10 deletions website/src/components/Edit/EditPage.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,32 @@ import { sentenceCase } from 'change-case';
import { beforeEach, describe, expect, test } from 'vitest';

import { EditPage } from './EditPage.tsx';
import { defaultReviewData, editableEntry, metadataKey, testAccessToken, testOrganism } from '../../../vitest.setup.ts';
import type { UnprocessedMetadataRecord } from '../../types/backend.ts';
import {
defaultReviewData,
editableEntry,
metadataDisplayName,
metadataKey,
testAccessToken,
testOrganism,
} from '../../../vitest.setup.ts';
import { type UnprocessedMetadataRecord } from '../../types/backend.ts';
import type { InputField } from '../../types/config.ts';
import type { ClientConfig } from '../../types/runtimeConfig.ts';

const queryClient = new QueryClient();

const dummyConfig = { backendUrl: 'dummy' } as ClientConfig;
const inputFields = [
{
name: 'originalMetaDataField',
dispayName: 'Original Meta Data Field',
},
];
const groupedInputFields = new Map<string, InputField[]>([
[
'Header',
[
{
name: metadataKey,
displayName: metadataDisplayName,
},
],
],
]);

function renderEditPage({
editedData = defaultReviewData,
Expand All @@ -31,7 +44,7 @@ function renderEditPage({
dataToEdit={editedData}
clientConfig={clientConfig}
accessToken={testAccessToken}
inputFields={inputFields}
groupedInputFields={groupedInputFields}
submissionDataTypes={{ consensusSequences: allowSubmissionOfConsensusSequences }}
/>
</QueryClientProvider>,
Expand Down Expand Up @@ -98,7 +111,7 @@ describe('EditPage', () => {
await userEvent.type(screen.getByDisplayValue(editableEntry), someTextToAdd);

expectTextInSequenceData.originalMetadata({
[metadataKey]: editableEntry + someTextToAdd,
[metadataDisplayName]: editableEntry + someTextToAdd,
});
const undoButton = document.querySelector(`.tooltip[data-tip="Revert to: ${editableEntry}"]`);
expect(undoButton).not.toBeNull();
Expand Down
95 changes: 50 additions & 45 deletions website/src/components/Edit/EditPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type EditPageProps = {
clientConfig: ClientConfig;
dataToEdit: SequenceEntryToEdit;
accessToken: string;
inputFields: InputField[];
groupedInputFields: Map<string, InputField[]>;
submissionDataTypes: SubmissionDataTypes;
};

Expand Down Expand Up @@ -75,7 +75,7 @@ const InnerEditPage: FC<EditPageProps> = ({
dataToEdit,
clientConfig,
accessToken,
inputFields,
groupedInputFields,
submissionDataTypes,
}) => {
const [editedMetadata, setEditedMetadata] = useState(mapMetadataToRow(dataToEdit));
Expand Down Expand Up @@ -143,7 +143,7 @@ const InnerEditPage: FC<EditPageProps> = ({
<EditableOriginalData
editedMetadata={editedMetadata.filter(({ key }) => key !== ACCESSION_FIELD)}
setEditedMetadata={setEditedMetadata}
inputFields={inputFields}
groupedInputFields={groupedInputFields}
/>
{submissionDataTypes.consensusSequences && (
<EditableOriginalSequences
Expand Down Expand Up @@ -305,13 +305,14 @@ function generateAndDownloadFastaFile(editedSequences: Row[], editedData: Sequen
type SubtitleProps = {
title: string;
bold?: boolean;
small?: boolean;
customKey?: string;
};
const Subtitle: FC<SubtitleProps> = ({ title, bold, customKey }) => (
const Subtitle: FC<SubtitleProps> = ({ title, bold, small, customKey }) => (
<Fragment key={snakeCase(customKey ?? title) + '_fragment'}>
<tr key={snakeCase(customKey ?? title) + '_spacing'} className='h-4' />
<tr key={snakeCase(customKey ?? title)} className='subtitle'>
<td className={(bold ?? false) ? 'font-semibold' : 'font-normal'} colSpan={3}>
<td className={`${(bold ?? false) ? 'font-semibold' : 'font-normal'} ${small && 'text-base'}`} colSpan={3}>
{title}
</td>
</tr>
Expand All @@ -321,50 +322,54 @@ const Subtitle: FC<SubtitleProps> = ({ title, bold, customKey }) => (
type EditableOriginalDataProps = {
editedMetadata: Row[];
setEditedMetadata: Dispatch<SetStateAction<Row[]>>;
inputFields: InputField[];
groupedInputFields: Map<string, InputField[]>;
};
const EditableOriginalData: FC<EditableOriginalDataProps> = ({ editedMetadata, setEditedMetadata, inputFields }) => (
const EditableOriginalData: FC<EditableOriginalDataProps> = ({
editedMetadata,
setEditedMetadata,
groupedInputFields,
}) => (
<>
<Subtitle title='Metadata' />
{inputFields.map((inputField) => {
let field;
field = editedMetadata.find((editedMetadataField) => editedMetadataField.key === inputField.name);

if (field === undefined) {
field = {
key: inputField.name,
value: '',
initialValue: '',
warnings: [],
errors: [],
};
}

if (!(inputField.noEdit !== undefined && inputField.noEdit)) {
return (
<EditableDataRow
label={inputField.displayName ?? sentenceCase(inputField.name)}
inputField={inputField.name}
key={'raw_metadata' + inputField.name}
row={field}
onChange={(editedRow: Row) =>
setEditedMetadata((prevRows: Row[]) => {
const relevantOldRow = prevRows.find((oldRow) => oldRow.key === editedRow.key);

if (relevantOldRow !== undefined) {
return prevRows.map((prevRow) =>
prevRow.key === editedRow.key
? { ...prevRow, value: editedRow.value }
: prevRow,
);
} else {
return [...prevRows, editedRow];
{Array.from(groupedInputFields.entries()).map(([group, fields]) => {
if (fields.length === 0) return undefined;
return (
<Fragment key={group}>
<Subtitle title={group} small />
{fields.map((inputField) => {
const field = editedMetadata.find(
(editedMetadataField) => editedMetadataField.key === inputField.name,
) ?? {
key: inputField.name,
value: '',
initialValue: '',
warnings: [],
errors: [],
};

return !inputField.noEdit ? (
<EditableDataRow
label={inputField.displayName ?? sentenceCase(inputField.name)}
inputField={inputField.name}
key={'raw_metadata' + inputField.name}
row={field}
onChange={(editedRow: Row) =>
setEditedMetadata((prevRows) => {
const relevantOldRow = prevRows.find((oldRow) => oldRow.key === editedRow.key);
return relevantOldRow
? prevRows.map((prevRow) =>
prevRow.key === editedRow.key
? { ...prevRow, value: editedRow.value }
: prevRow,
)
: [...prevRows, editedRow];
})
}
})
}
/>
);
}
/>
) : null;
})}
</Fragment>
);
})}
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
import { EditPage } from '../../../../../components/Edit/EditPage';
import { getRuntimeConfig, getSchema } from '../../../../../config';
import { cleanOrganism } from '../../../../../components/Navigation/cleanOrganism';
import { getGroupedInputFields, getRuntimeConfig, getSchema } from '../../../../../config';
import BaseLayout from '../../../../../layouts/BaseLayout.astro';
import { BackendClient } from '../../../../../services/backendClient';
import { getAccessToken } from '../../../../../utils/getAccessToken';
Expand All @@ -9,7 +10,16 @@ const version = Astro.params.version!;
const accession = Astro.params.accession!;
const organism = Astro.params.organism!;
const { inputFields } = getSchema(organism);
const { organism: cleanedOrganism } = cleanOrganism(Astro.params.organism);
if (!cleanedOrganism) {
return {
statusCode: 404,
body: 'Organism not found',
};
}
const groupedInputFields = getGroupedInputFields(cleanedOrganism.key, 'revise', true);
const accessToken = getAccessToken(Astro.locals.session)!;
const clientConfig = getRuntimeConfig().public;
Expand All @@ -27,7 +37,7 @@ const dataToEdit = await BackendClient.create().getDataToEdit(organism, accessTo
accessToken={accessToken}
dataToEdit={dataToEdit}
clientConfig={clientConfig}
inputFields={inputFields}
groupedInputFields={groupedInputFields}
submissionDataTypes={schema.submissionDataTypes}
client:load
/>
Expand Down
3 changes: 2 additions & 1 deletion website/vitest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export const testConfig = {
// See https://github.com/tailwindlabs/headlessui/issues/3268
vi.stubGlobal('ResizeObserver', ResizeObserver);

export const metadataKey = 'originalMetaDataField';
export const metadataKey = 'originalMetadataField';
export const metadataDisplayName = 'Original Metadata Field';
export const editableEntry = 'originalMetaDataValue';
export const defaultReviewData: SequenceEntryToEdit = {
accession: '1',
Expand Down

0 comments on commit ec43406

Please sign in to comment.