Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import { IconButton } from '@carbon/react';
import { Draggable, Edit, TrashCan, Copy } from '@carbon/react/icons';
import { showModal, ChevronDownIcon, ChevronUpIcon } from '@openmrs/esm-framework';
import MarkdownWrapper from '../markdown-wrapper/markdown-wrapper';
import type { Question, Schema } from '@types';
import type { FormField } from '@openmrs/esm-form-engine-lib';
import type { Schema } from '@types';
import styles from './draggable-question.scss';

interface DraggableQuestionProps {
handleDuplicateQuestion: (question: Question, pageId: number, sectionId: number, questionId?: number) => void;
handleDuplicateQuestion: (question: FormField, pageId: number, sectionId: number, questionId?: number) => void;
onSchemaChange: (schema: Schema) => void;
pageIndex: number;
question: Question;
question: FormField;
questionCount: number;
questionIndex: number;
schema: Schema;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import { showModal, showSnackbar } from '@openmrs/esm-framework';
import DraggableQuestion from './draggable/draggable-question.component';
import EditableValue from './editable/editable-value.component';
import type { DragEndEvent } from '@dnd-kit/core';
import type { FormSchema } from '@openmrs/esm-form-engine-lib';
import type { Schema, Question } from '@types';
import type { FormSchema, FormField } from '@openmrs/esm-form-engine-lib';
import type { Schema } from '@types';
import styles from './interactive-builder.scss';

interface ValidationError {
Expand All @@ -37,7 +37,7 @@ interface InteractiveBuilderProps {
}

interface SubQuestionProps {
question: Question;
question: FormField;
pageIndex: number;
sectionIndex: number;
questionIndex: number;
Expand Down Expand Up @@ -257,9 +257,9 @@ const InteractiveBuilder: React.FC<InteractiveBuilderProps> = ({
);

const duplicateQuestion = useCallback(
(question: Question, pageId: number, sectionId: number, questionId?: number) => {
(question: FormField, pageId: number, sectionId: number, questionId?: number) => {
try {
const questionToDuplicate: Question = JSON.parse(JSON.stringify(question));
const questionToDuplicate: FormField = JSON.parse(JSON.stringify(question));
questionToDuplicate.id = questionToDuplicate.id + 'Duplicate';

if (Number.isInteger(questionId)) {
Expand Down Expand Up @@ -340,7 +340,7 @@ const InteractiveBuilder: React.FC<InteractiveBuilderProps> = ({
pageIndex: number,
sectionIndex: number,
questionId: string | number,
newQuestion: Question,
newQuestion: FormField,
): Schema {
if (activeQuestion.type === 'question') {
const newSchema = { ...schema };
Expand Down Expand Up @@ -419,7 +419,7 @@ const InteractiveBuilder: React.FC<InteractiveBuilderProps> = ({
return errors || [];
};

const getValidationError = (question: Question) => {
const getValidationError = (question: FormField) => {
const errorField: ValidationError = validationResponse.find(
(error) =>
error.field.label === question.label && error.field.id === question.id && error.field.type === question.type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import {
import { showSnackbar } from '@openmrs/esm-framework';
import { useForms } from '@hooks/useForms';
import { useClobdata } from '@hooks/useClobdata';
import { type Form as FormType, type Schema, type Page, type Section, type Question } from '@types';
import type { FormPage, FormSection, FormField } from '@openmrs/esm-form-engine-lib';
import type { Form as FormType, Schema } from '@types';
import styles from './add-form-reference.scss';

interface AddFormReferenceModalProps {
Expand All @@ -41,9 +42,9 @@ const AddFormReferenceModal: React.FC<AddFormReferenceModalProps> = ({
}) => {
const { t } = useTranslation();
const [selectedForm, setSelectedForm] = useState<FormType>(null);
const [pages, setPages] = useState<Page[]>([]);
const [selectedPage, setSelectedPage] = useState<Page>(null);
const [selectedSection, setSelectedSection] = useState<Section>(null);
const [pages, setPages] = useState<FormPage[]>([]);
const [selectedPage, setSelectedPage] = useState<FormPage>(null);
const [selectedSection, setSelectedSection] = useState<FormSection>(null);
const [excludedQuestions, setExcludedQuestions] = useState<string[]>([]);
const { forms, error, isLoading } = useForms();
const { clobdata, isLoadingClobdata, clobdataError } = useClobdata(selectedForm);
Expand All @@ -61,18 +62,18 @@ const AddFormReferenceModal: React.FC<AddFormReferenceModalProps> = ({
}
}, [clobdata]);

const handleSelectedPage = useCallback(({ selectedItem }: { selectedItem: Page }) => {
const handleSelectedPage = useCallback(({ selectedItem }: { selectedItem: FormPage }) => {
setSelectedPage(selectedItem);
setSelectedSection(null);
setExcludedQuestions([]);
}, []);

const handleSelectedSections = useCallback((section: Section) => {
const handleSelectedSections = useCallback((section: FormSection) => {
setSelectedSection(section);
setExcludedQuestions([]);
}, []);

const handleExcludedQuestions = useCallback((question: Question, checked: Boolean) => {
const handleExcludedQuestions = useCallback((question: FormField, checked: Boolean) => {
setExcludedQuestions((prev) => {
if (!checked) {
return prev.some((q) => q === question.id) ? prev : [...prev, question.id];
Expand Down Expand Up @@ -211,7 +212,7 @@ const AddFormReferenceModal: React.FC<AddFormReferenceModalProps> = ({
label: page.label,
sections: page.sections,
}))}
itemToString={(item: Page) => (item ? item.label : '')}
itemToString={(item: FormPage) => (item ? item.label : '')}
onChange={handleSelectedPage}
selectedItem={selectedPage}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import React from 'react';
import { useTranslation } from 'react-i18next';
import { Button, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
import { showSnackbar } from '@openmrs/esm-framework';
import type { Question, Schema } from '@types';
import type { FormField } from '@openmrs/esm-form-engine-lib';
import type { Schema } from '@types';

interface DeleteQuestionModal {
closeModal: () => void;
onSchemaChange: (schema: Schema) => void;
pageIndex: number;
question: Question;
question: FormField;
questionIndex: number;
schema: Schema;
sectionIndex: number;
Expand Down
5 changes: 3 additions & 2 deletions src/resources/form-validator.resource.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
import type { Question, Schema } from '@types';
import type { FormField } from '@openmrs/esm-form-engine-lib';
import type { Schema } from '@types';
import type { ConfigObject } from '../config-schema';

interface Field {
Expand Down Expand Up @@ -32,7 +33,7 @@ export const handleFormValidation = async (
const asyncTasks: Array<Promise<void>> = [];

parsedForm.pages?.forEach((page) =>
page.sections?.forEach((section: { questions: Array<Question> }) =>
page.sections?.forEach((section: { questions: Array<FormField> }) =>
section.questions?.forEach((question) => {
asyncTasks.push(
handleQuestionValidation(question, errors, configObject, warnings),
Expand Down
170 changes: 8 additions & 162 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import type { OpenmrsResource } from '@openmrs/esm-framework';
import type {
OpenmrsFormResource,
FormField,
ProgramState,
ReferencedForm,
RenderType,
RequiredFieldProps,
FormReference,
} from '@openmrs/esm-form-engine-lib';
import type { FormSchema, ProgramState } from '@openmrs/esm-form-engine-lib';
import type { AuditInfo } from './components/audit-details/audit-details.component';
import type { questionTypes } from '@constants';

// Extend FormSchema to include description property
export interface FormBuilderSchema extends FormSchema {
description?: string;
}

export interface Form {
uuid: string;
name: string;
Expand Down Expand Up @@ -50,117 +47,14 @@ export type QuestionType = (typeof questionTypes)[number];

export type DatePickerType = 'both' | 'calendar' | 'timer';

export interface Schema {
name: string;
pages: Array<{
label: string;
sections: Array<{
label: string;
isExpanded: string;
reference?: FormReference;
questions: Array<{
id: string;
label?: string;
value?: string;
type: string;
required?: string | boolean | RequiredFieldProps;
questionInfo?: string;
questionOptions: {
type?: string;
concept?: string;
answers?: Array<Record<string, string>>;
rendering: RenderType;
max?: string;
min?: string;
conceptMappings?: Array<Record<string, string>>;
};
questions?: Array<Question>;
validators?: Array<Record<string, string>>;
}>;
}>;
}>;
processor: string;
uuid: string;
encounterType: string;
referencedForms: Array<ReferencedForm>;
version?: string;
description?: string;
encounter?: string | OpenmrsEncounter;
allowUnspecifiedAll?: boolean;
defaultPage?: string;
readonly?: string | boolean;
inlineRendering?: 'single-line' | 'multiline' | 'automatic';
markdown?: unknown;
postSubmissionActions?: Array<{ actionId: string; config?: Record<string, unknown> }>;
formOptions?: {
usePreviousValueDisabled: boolean;
};
translations?: Record<string, string>;
}
// Using extended FormBuilderSchema instead of FormSchema
export type Schema = FormBuilderSchema;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just directly import all types from the form-engine-lib itself and remove them from this file, we shouldn't need to export from here. Even though that would mean that we need to update a lot of files, it just seems redundant to export them from here again

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just directly import all types from the form-engine-lib itself and remove them from this file, we shouldn't need to export from here. Even though that would mean that we need to update a lot of files, it just seems redundant to export them from here again

You're absolutely right! Re-exporting these types is redundant. I'll update the codebase to import types directly from @openmrs/openmrs-form-engine-lib where they're used, rather than going through this intermediary file. This will make the dependencies clearer and reduce unnecessary abstraction.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we still re-exporting the schema from here? If it’s because the type from form-engine-lib is missing the description property, it’s highly possible that it's a mistake. Could you ask this in the #form-engine channel on Slack, and fix it in the form engine?


export interface SchemaContextType {
schema: Schema;
setSchema: (schema: Schema) => void;
}

export interface Page {
label: string;
sections: Array<Section>;
}

export interface Section {
label: string;
questions: Array<Question>;
isExpanded: string | boolean;
}

export interface Question {
id: string;
label?: string;
value?: any;
type: string;
questionOptions: QuestionOptions;
datePickerFormat?: DatePickerType;
questions?: Array<Question>;
required?: string | boolean | RequiredFieldProps;
validators?: Array<Record<string, string>>;
questionInfo?: string;
}

export interface QuestionOptions {
rendering: RenderType;
answers?: Array<Record<string, string>>;
concept?: string;
conceptMappings?: Array<ConceptMapping>;
max?: string;
min?: string;
isSearchable?: boolean;
attributeType?: string;
calculate?: {
calculateExpression: string;
};
rows?: number;
orderSettingUuid?: string;
orderType?: string;
identifierType?: string;
selectableOrders?: Array<
| {
concept: string;
label: string;
}
| Record<string, any>
>;
weekList?: [];
showComment?: boolean;
showDate?: string;
programUuid?: string;
workflowUuid?: string;
toggleOptions?: {
labelTrue: string;
labelFalse: string;
};
}

export interface Answer {
concept: string;
label: string;
Expand Down Expand Up @@ -208,54 +102,6 @@ export interface PersonAttributeType {
};
}

export interface OpenmrsEncounter {
uuid?: string;
encounterDatetime?: string | Date;
patient?: OpenmrsResource | string;
location?: OpenmrsResource | string;
encounterType?: OpenmrsResource | string;
obs?: Array<OpenmrsObs>;
orders?: Array<OpenmrsResource>;
voided?: boolean;
visit?: OpenmrsResource | string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
encounterProviders?: Array<Record<string, any>>;
form?: OpenmrsFormResource;
}

export type SessionMode = 'edit' | 'enter' | 'view' | 'embedded-view';

export interface PostSubmissionAction {
applyAction(
formSession: {
patient: fhir.Patient;
encounters: Array<OpenmrsEncounter>;
sessionMode: SessionMode;
},
config?: Record<string, unknown>,
enabled?: string,
): void;
}

export interface OpenmrsObs extends OpenmrsResource {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
concept?: any;
obsDatetime?: string | Date;
obsGroup?: OpenmrsObs;
groupMembers?: Array<OpenmrsObs>;
comment?: string;
location?: OpenmrsResource;
order?: OpenmrsResource;
encounter?: OpenmrsResource;
voided?: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value?: any;
formFieldPath?: string;
formFieldNamespace?: string;
status?: string;
interpretation?: string;
}

export interface Program {
uuid: string;
name: string;
Expand Down