Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
f705fd6
feat(studyRegistrationForm): Able to render part of UI and trigger on…
jarvisraymond-uchicago Jul 20, 2026
7c7a40d
feat(studyRegistrationForm): Got Select element to pass data to onSub…
jarvisraymond-uchicago Jul 20, 2026
bdad59d
feat(studyRegistrationForm): Got Tag element to pass data to onSubmit…
jarvisraymond-uchicago Jul 20, 2026
bb88908
feat(studyRegistrationForm): Got getClinicalTrialMetadata to respond
jarvisraymond-uchicago Jul 21, 2026
5d8fcdb
feat(studyRegistrationForm): Updated study details header buttons to …
jarvisraymond-uchicago Jul 22, 2026
caf9dc8
feat(studyRegistrationForm): fixed userCanRegisterStudy
jarvisraymond-uchicago Jul 23, 2026
14038df
feat(studyRegistrationForm): got studyUID to pass to form from discov…
jarvisraymond-uchicago Jul 23, 2026
ff42e16
feat(studyRegistrationForm): Got dropdown to prepopulate with user re…
jarvisraymond-uchicago Jul 27, 2026
27f916f
feat(studyRegistrationForm): Updated study formating to match data po…
jarvisraymond-uchicago Jul 27, 2026
8d965fd
feat(studyRegistrationForm): added form validation for CEDAR User UUID
jarvisraymond-uchicago Jul 28, 2026
b9cb36d
feat(studyRegistrationForm): Added form validation for ClinicalTrials…
jarvisraymond-uchicago Jul 29, 2026
5cadd26
feat(studyRegistrationForm): Updated submit func to use getClinicalTr…
jarvisraymond-uchicago Jul 29, 2026
ecb8f6e
feat(studyRegistrationForm): preprocessStudyRegistrationMetadata retu…
jarvisraymond-uchicago Jul 30, 2026
25320ef
feat(studyRegistrationForm): Solved issue with dropdown pre-populating
jarvisraymond-uchicago Jul 31, 2026
80d826d
feat(studyRegistrationForm): Added request to cedarAPI using RTK Query
jarvisraymond-uchicago Aug 3, 2026
950884f
feat(studyRegistrationForm): Moved API services logic to gen3core
jarvisraymond-uchicago Aug 3, 2026
8aa3529
feat(studyRegistrationForm): Updated MDS API to use RTK Query, able t…
jarvisraymond-uchicago Aug 4, 2026
34dc970
feat(studyRegistrationForm): Fix bug were form crashes if there are n…
jarvisraymond-uchicago Aug 5, 2026
7e81e24
feat(studyRegistration): Formatted form, updated Error UI
jarvisraymond-uchicago Aug 6, 2026
296a2f7
feat(studyRegistration): added storybook, cleaned up Error UI
jarvisraymond-uchicago Aug 7, 2026
e6b746e
feat(studyRegistrationForm): Replaced proxy.ts with version from develop
jarvisraymond-uchicago Aug 10, 2026
225078d
Merge branch 'develop' into feat/studyRegistrationForm
jarvisraymond-uchicago Aug 10, 2026
619ab0f
feat(studyRegistrationForm): Fixed TS issues and oxlint issue
jarvisraymond-uchicago Aug 10, 2026
7e14e4d
feat(studyRegistrationForm): Created a TS type for the form config
jarvisraymond-uchicago Aug 10, 2026
2eca56f
feat(studyRegistrationForm): Minor code cleanup
jarvisraymond-uchicago Aug 10, 2026
3bfd653
Merge branch 'develop' into feat/studyRegistrationForm
jarvisraymond-uchicago Aug 11, 2026
9cfd65f
feat(studyRegistrationForm): fixed validator for clinicalTrial ID, fi…
jarvisraymond-uchicago Aug 11, 2026
8cbd296
feat(studyRegistrationForm): fixed oxlint warning
jarvisraymond-uchicago Aug 11, 2026
1ebc5b6
feat(studyRegistrationForm): fixed more oxlint warnings
jarvisraymond-uchicago Aug 11, 2026
43cb9a9
feat(studyRegistrationForm): fixed more oxlint warnings
jarvisraymond-uchicago Aug 11, 2026
bf17419
feat(studyRegistrationForm): fixed more oxlint warnings on createCeda…
jarvisraymond-uchicago Aug 11, 2026
2e3f5a6
feat(studyRegistrationForm): fixed more oxlint warnings on mdsApi.ts
jarvisraymond-uchicago Aug 11, 2026
fed6a38
feat(studyREgistrationForm): fixed OXLINT warnings in updateStudyInMDS
jarvisraymond-uchicago Aug 11, 2026
938c52b
Merge branch 'develop' into feat/studyRegistrationForm
jarvisraymond-uchicago Aug 11, 2026
760d542
Merge branch 'develop' into feat/studyRegistrationForm
jarvisraymond-uchicago Aug 12, 2026
e986186
feat(studyREgistrationForm): fixed npm run build issues related to th…
jarvisraymond-uchicago Aug 11, 2026
48ec1d3
feat(studyREgistrationForm): fixed npm run build issues related to th…
jarvisraymond-uchicago Aug 11, 2026
9098d04
feat(studyRegistrationForm): resolved build issues in userCanRegister…
jarvisraymond-uchicago Aug 12, 2026
d022e7c
feat(studyRegistrationForm): resolved build issues in userCanRegister…
jarvisraymond-uchicago Aug 12, 2026
2320648
feat(studyRegistrationForm): typed key as string in useStudyRegistration
jarvisraymond-uchicago Aug 12, 2026
4d822b5
feat(studyRegistrationForm): Fixed OXLINT issues in Form.tsx
jarvisraymond-uchicago Aug 12, 2026
000a3d9
feat(studyRegistrationForm): Fixed OXLINT issues in Form.tsx
jarvisraymond-uchicago Aug 12, 2026
5514215
feat(studyRegistrationForm): Fixed OXLINT issues in Form.tsx
jarvisraymond-uchicago Aug 12, 2026
d8f7f1d
feat(studyRegistrationForm): Fixed OXLINT issues in Form.tsx
jarvisraymond-uchicago Aug 12, 2026
801614b
feat(studyRegistrationForm): fixed oxlint errors in getClinicalTrialM…
jarvisraymond-uchicago Aug 12, 2026
5fa1abd
feat(studyRegistrationForm): Fixed OXLINT errors in preprocessSTudyRe…
jarvisraymond-uchicago Aug 12, 2026
3d19d46
feat(studyRegistrationForm): Fixed FormContentViews.stories.tsx OXLIN…
jarvisraymond-uchicago Aug 12, 2026
f7ec667
feat(studyRegistrationForm): Fixed FormContentViews.tsx OXLINT Warnings
jarvisraymond-uchicago Aug 12, 2026
592e158
feat(studyRegistrationForm): Fixed more OXLINT Warnings
jarvisraymond-uchicago Aug 12, 2026
d9e9eca
feat(studyDetailsHeaderButtons): Fixed OXLINT warnings on StudyDetail…
jarvisraymond-uchicago Aug 12, 2026
cb6060e
feat(studyDetailsHeaderButtons): Fixed OXLINT warnings in StudyRegist…
jarvisraymond-uchicago Aug 12, 2026
984283f
feat(studyRegistrationForm): Resolved issues associated with useStudy…
jarvisraymond-uchicago Aug 13, 2026
8057641
feat(studyRegistrationForm): Resolved issues associated with useStudy…
jarvisraymond-uchicago Aug 13, 2026
439a539
feat(studyRegistrationForm): fixed broken study data repository dropdown
jarvisraymond-uchicago Aug 13, 2026
f1ea5fb
feat(studyRegistrationForm): fixed broken study data repository dropd…
jarvisraymond-uchicago Aug 13, 2026
cdc52fb
feat(studyRegistrationForm): fixed broken error messaging in CEDAR US…
jarvisraymond-uchicago Aug 13, 2026
6f8c9c2
Merge branch 'develop' into feat/studyRegistrationForm
jarvisraymond-uchicago Aug 14, 2026
94d0c6d
feat(studyRegistrationForm): reverted unintentially changed proxy.ts
jarvisraymond-uchicago Aug 14, 2026
b55ddb7
feat(studyRegistrationForm): fixed broken storybook
jarvisraymond-uchicago Aug 14, 2026
524b9a8
feat(studyRegistrationForm): fixed broken storybook
jarvisraymond-uchicago Aug 14, 2026
a3b4d8e
feat(studyRegistrationForm): General code cleanup
jarvisraymond-uchicago Aug 14, 2026
825a132
feat(studyRegistrationForm): ran build, updated proxy.ts
jarvisraymond-uchicago Aug 14, 2026
608ea86
feat(studyRegistrationForm): Reverted inadvertant changes to proxy.ts
jarvisraymond-uchicago Aug 14, 2026
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
44 changes: 44 additions & 0 deletions packages/core/src/features/cedar/cedarApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { gen3Api } from '../gen3';

export interface CreateCedarPayload {
cedar_user_uuid: string;
metadata: {
study_metadata: {
metadata_location: {
nih_application_id?: string;
};
minimal_info: {
study_name?: string;
study_description?: string;
};
};
clinicaltrials_gov?: string;
};
}

export interface CreateCedarResponse {
cedar_instance_id?: string;
}

export const cedarApi = gen3Api.injectEndpoints({
endpoints: (builder) => ({
createCedarInstance: builder.mutation<
CreateCedarResponse,
{ cedarWrapperURL: string; payload: CreateCedarPayload }
>({
query: ({ cedarWrapperURL, payload }) => ({
url: `${cedarWrapperURL}/create`,
method: 'POST',
body: payload,
}),
}),
}),
});

export const { useCreateCedarInstanceMutation } = cedarApi;

// Export mutation trigger function type
type CreateCedarMutationResult = ReturnType<
typeof useCreateCedarInstanceMutation
>;
export type CreateCedarMutationTriggerType = CreateCedarMutationResult[0];
58 changes: 58 additions & 0 deletions packages/core/src/features/cedar/createCedarInstance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { CreateCedarMutationTriggerType, CreateCedarPayload } from './cedarApi';
import type { MetadataToRegister } from './types';

export const createCEDARInstance = async (
cedarWrapperURL: string,
cedarUserUUID: string,
metadataToRegister: MetadataToRegister,
createCedarQuery: CreateCedarMutationTriggerType,
): Promise<unknown> => {
const STUDY_DATA_FIELD = 'gen3_discovery';

// Deep clone to prevent mutating original metadata
let updatedMetadataToRegister = JSON.parse(
JSON.stringify(metadataToRegister),
);

const payload: CreateCedarPayload = {
cedar_user_uuid: cedarUserUUID,
metadata: {
study_metadata: {
metadata_location: {
nih_application_id:
metadataToRegister[STUDY_DATA_FIELD]?.study_metadata
?.metadata_location?.nih_application_id,
},
minimal_info: {
study_name:
metadataToRegister[STUDY_DATA_FIELD]?.study_metadata?.minimal_info
?.study_name,
study_description:
metadataToRegister[STUDY_DATA_FIELD]?.study_metadata?.minimal_info
?.study_description,
},
},
clinicaltrials_gov: metadataToRegister.clinicaltrials_gov,
},
};

try {
// Call the mutation trigger passed in from the component
const data = await createCedarQuery({
cedarWrapperURL,
payload,
}).unwrap();

updatedMetadataToRegister[
STUDY_DATA_FIELD
].study_metadata.metadata_location.cedar_study_level_metadata_template_instance_ID =
data.cedar_instance_id || '';

return updatedMetadataToRegister;
} catch (err: unknown) {
const errorMsg = JSON.stringify(err);
return {
error: `Request to create CEDAR instance failed: ${errorMsg}`,
};
}
};
2 changes: 2 additions & 0 deletions packages/core/src/features/cedar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { createCEDARInstance } from './createCedarInstance';
export { cedarApi } from './cedarApi';
28 changes: 28 additions & 0 deletions packages/core/src/features/cedar/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export interface StudyMetadataLocation {
nih_application_id?: string;
cedar_study_level_metadata_template_instance_ID?: string;
}

export interface MinimalInfo {
study_name?: string;
study_description?: string;
}

export interface StudyMetadata {
metadata_location?: StudyMetadataLocation;
minimal_info?: MinimalInfo;
}

export interface Gen3DiscoveryField {
study_metadata: {
metadata_location: StudyMetadataLocation;
minimal_info?: MinimalInfo;
};
[key: string]: unknown;
}

export interface MetadataToRegister {
gen3_discovery: Gen3DiscoveryField;
clinicaltrials_gov?: string | undefined;
[key: string]: unknown;
}
6 changes: 6 additions & 0 deletions packages/core/src/features/updateStudyInMDS/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export { updateStudyInMDS } from './updateStudyInMDS';
export { mdsApi, useUpdateStudyInMDSMutation } from './mdsApi';
export type {
UpdateStudyInMdsMutationTriggerType,
UpdateMdsStudyArgs,
} from './mdsApi';
27 changes: 27 additions & 0 deletions packages/core/src/features/updateStudyInMDS/mdsApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { gen3Api } from '../gen3';

export interface UpdateMdsStudyArgs {
mdsURL: string;
metadataID: string;
metadataToUpdate: Record<string, unknown>;
}

export const mdsApi = gen3Api.injectEndpoints({
endpoints: (builder) => ({
updateStudyInMDS: builder.mutation<void, UpdateMdsStudyArgs>({
query: ({ mdsURL, metadataID, metadataToUpdate }) => ({
url: `${mdsURL}/metadata/${metadataID}?overwrite=true`,
method: 'POST',
body: metadataToUpdate,
}),
}),
}),
});

export const { useUpdateStudyInMDSMutation } = mdsApi;

type UpdateMdsStudyMutationResult = ReturnType<
typeof useUpdateStudyInMDSMutation
>;
export type UpdateStudyInMdsMutationTriggerType =
UpdateMdsStudyMutationResult[0];
23 changes: 23 additions & 0 deletions packages/core/src/features/updateStudyInMDS/updateStudyInMDS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { toString } from 'lodash';
import type { UpdateStudyInMdsMutationTriggerType } from './mdsApi';

export const updateStudyInMDS = async (
mdsURL: string,
metadataID: string,
metadataToUpdate: Record<string, unknown> = {},
updateMdsQuery: UpdateStudyInMdsMutationTriggerType,
): Promise<unknown> => {
try {
const response = await updateMdsQuery({
mdsURL,
metadataID,
metadataToUpdate,
}).unwrap();

return response;
} catch (error: unknown) {
throw new Error(
`Request for update study data failed: ${(error instanceof Error && error.message) || toString(error)}`,
);
}
};
2 changes: 2 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export * from './dataAccess';
// Gen3 services API's
export * from './features/aiSearch';
export * from './features/authz';
export * from './features/cedar';
export * from './features/updateStudyInMDS';
export * from './features/cohort';
export * from './features/dataLibrary';
export * from './features/drsResolver';
Expand Down
53 changes: 40 additions & 13 deletions packages/frontend/src/components/Content/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import React from 'react';

import FormContent, { FormContentProps, FormContentType } from './FormContent';
import type { FormContentProps } from './FormContent';
import FormContent, { FormContentType } from './FormContent';
import { Button, Text } from '@mantine/core';
import { useForm, FormValidateInput, isEmail, isNotEmpty } from '@mantine/form';
import type { FormValidateInput, UseFormReturnType } from '@mantine/form';
import { useForm, isEmail, isNotEmpty } from '@mantine/form';
import { isCedarUUIDValid, isClinicalTrialIDValid } from './formValidators';

interface FormPropsBody extends Omit<FormContentProps, 'keyString' | 'form'> {
readonly errorText: string; // text to display on error
export interface FormPropsBody extends Omit<
FormContentProps,
'keyString' | 'form'
> {
readonly errorText?: string; // text to display on error
readonly variable?: string; // form feild variable name
readonly initialValue?: string | boolean; // optional starting value
readonly required?: boolean;
}

export interface FormOnSubmitReturnProps {
Expand All @@ -22,7 +27,9 @@ export interface FormProps {
readonly submitButtonText?: string; // submit Button Text defalts to Submit
readonly showResetButton?: boolean; // Determines if the reset button should be visible
readonly body: FormPropsBody[]; // array of FormContent
readonly onSubmit: (values: FormOnSubmitReturnProps) => void | Promise<any>; // function to trigger on form submit
readonly onSubmit: (
values: FormOnSubmitReturnProps,
) => void | Promise<unknown>; // function to trigger on form submit
readonly errorMessage?: string; // error messaage to display above submit button
}

Expand All @@ -45,10 +52,10 @@ const Form = ({
onSubmit,
errorMessage,
}: FormProps) => {
const initialValues: { [key: string]: string | boolean } = {};
const validate: FormValidateInput<any> = {};
const initialValues: FormOnSubmitReturnProps = {};
const validate: FormValidateInput<FormOnSubmitReturnProps> = {};

const bodyWithKey: Omit<FormContentProps, 'form'>[] = body.map(
const bodyWithKey: (FormPropsBody & { keyString: string })[] = body.map(
(item, index) => {
const itemKey =
item.variable ||
Expand All @@ -65,8 +72,19 @@ const Form = ({
const isvalidEmail = item.errorText || 'Invalid email';
validate[itemKey] = isEmail(isvalidEmail);
}
if (item.type === FormContentType.ClinicalTrialID) {
validate[itemKey] = isClinicalTrialIDValid(item.errorText);
}
if (item.required) {
switch (item.type) {
case FormContentType.CedarUserUUID: {
validate[itemKey] = isCedarUUIDValid(item.errorText);
break;
}
case FormContentType.ClinicalTrialID: {
validate[itemKey] = isClinicalTrialIDValid(item.errorText);
break;
}
case FormContentType.Email: {
const isValidEmail = item.errorText || 'Invalid email';
validate[itemKey] = isEmail(isValidEmail);
Expand All @@ -89,7 +107,7 @@ const Form = ({
},
);

const form = useForm({
const form = useForm<FormOnSubmitReturnProps>({
mode: 'uncontrolled',
validateInputOnBlur: true,
initialValues,
Expand All @@ -98,8 +116,17 @@ const Form = ({

return (
<form onSubmit={form.onSubmit(onSubmit)} className={className}>
{bodyWithKey?.map((content, index) => (
<FormContent {...content} form={form} key={index} />
{bodyWithKey.map((content, index) => (
<FormContent
{...content}
form={
form as unknown as UseFormReturnType<
Record<string, unknown>,
(values: Record<string, unknown>) => Record<string, unknown>
>
}
key={index}
/>
))}
{errorMessage && <Text c="red">{errorMessage}</Text>}
<Button
Expand Down
Loading
Loading