Skip to content

Commit

Permalink
(refactor) O3-4145: Break question modal into individual components (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
NethmiRodrigo authored Jan 30, 2025
1 parent 72df886 commit e5c6f76
Show file tree
Hide file tree
Showing 106 changed files with 3,506 additions and 2,592 deletions.
51 changes: 28 additions & 23 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,52 @@
},
"extends": [
"eslint:recommended",
"plugin:playwright/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:jest-dom/recommended",
"plugin:testing-library/react"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": true,
"tsconfigRootDir": "__dirname"
},
"plugins": ["@typescript-eslint", "import", "react-hooks", "testing-library"],
"plugins": ["@typescript-eslint", "import", "jest-dom", "react-hooks", "testing-library"],
"root": true,
"overrides": [
{
"files": ["e2e/**"],
"excludedFiles":["src/**"],
"extends": ["plugin:playwright/recommended"]
}
],
"rules": {
"import/no-duplicates": "error",
"react-hooks/exhaustive-deps": "warn",
"react-hooks/rules-of-hooks": "error",
// Disabling these rules for now just to keep the diff small. We'll enable them one by one as we go.
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-explicit-any": "off",
// not hugely concerned about accidental implicit type coercions for now https://typescript-eslint.io/rules/no-base-to-string
"@typescript-eslint/no-base-to-string": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/triple-slash-reference": "off",
// The following rules need `noImplicitAny` to be set to `true` in our tsconfig. They are too restrictive for now, but should be reconsidered in future
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/unbound-method": "off",
// Nitpicky. Prefer `interface T` over type T
"@typescript-eslint/consistent-type-definitions": "error",
"@typescript-eslint/consistent-type-exports": "error",
"@typescript-eslint/no-floating-promises": "off",
// Use `import type` instead of `import` for type imports
// Use `import type` instead of `import` for type imports https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how
"@typescript-eslint/consistent-type-imports": [
"error",
{
"fixStyle": "inline-type-imports"
}
],
// Use Array<T> instead of T[] consistently
"@typescript-eslint/array-type": [
"import/no-duplicates": "error",
"no-console": [
"error",
{
"default": "generic"
"allow": ["warn", "error"]
}
],
"no-console": ["error", { "allow": ["warn", "error"] }],
"no-unsafe-optional-chaining": "off",
"no-explicit-any": "off",
"no-extra-boolean-cast": "off",
"no-prototype-builtins": "off",
"no-useless-escape": "off",
"no-restricted-imports": [
"error",
{
Expand All @@ -73,6 +75,9 @@
}
]
}
]
],
"prefer-const": "off",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
}
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ dist/
# EditorConfig
.editorconfig

.DS_Store
.idea
.vscode
.turbo
/test-results/
/playwright-report/
Expand Down
1 change: 0 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ yarn.lock

# by file type
**/*.css
**/*.scss
**/*.md
**/*.json
29 changes: 16 additions & 13 deletions e2e/specs/interactive-builder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ test('Create a form using the interactive builder', async ({ page, context }) =>
},
],
},
validators: [],
},
],
},
Expand Down Expand Up @@ -75,6 +74,7 @@ test('Create a form using the interactive builder', async ({ page, context }) =>
});

await test.step('And then I click on `Create Form`', async () => {
await expect(formBuilderPage.createFormButton()).toBeEnabled();
await formBuilderPage.createFormButton().click();
await expect(formBuilderPage.page.getByText(/form created/i)).toBeVisible();
expect(JSON.parse(await formBuilderPage.schemaEditorContent().textContent())).toEqual({
Expand All @@ -92,6 +92,7 @@ test('Create a form using the interactive builder', async ({ page, context }) =>
});

await test.step('And then I click on `Save`', async () => {
await expect(formBuilderPage.savePageButton()).toBeEnabled();
await formBuilderPage.savePageButton().click();
await expect(formBuilderPage.page.getByText(/new page created/i)).toBeVisible();
expect(JSON.parse(await formBuilderPage.schemaEditorContent().textContent())).toEqual({
Expand All @@ -114,6 +115,7 @@ test('Create a form using the interactive builder', async ({ page, context }) =>
});

await test.step('And then I click on `Save`', async () => {
await expect(formBuilderPage.saveQuestionButton()).toBeEnabled();
await formBuilderPage.saveSectionButton().click();
await expect(formBuilderPage.page.getByText(/new section created/i)).toBeVisible();
expect(JSON.parse(await formBuilderPage.schemaEditorContent().textContent())).toEqual({
Expand Down Expand Up @@ -141,22 +143,10 @@ test('Create a form using the interactive builder', async ({ page, context }) =>
await formBuilderPage.addQuestionButton().click();
});

await test.step('And then I type in the question label', async () => {
await formBuilderPage.questionLabelInput().fill(formDetails.pages[0].sections[0].questions[0].label);
});

await test.step('And then I type in the question id', async () => {
await formBuilderPage.questionIdInput().fill(formDetails.pages[0].sections[0].questions[0].id);
});

await test.step('And then I set the question type to required', async () => {
await formBuilderPage.page
.getByRole('group', { name: /Is this question a required/i })
.locator('span')
.nth(2)
.click();
});

await test.step('And then I set the question type to obs', async () => {
await formBuilderPage.questionTypeDropdown().selectOption('obs');
});
Expand All @@ -165,6 +155,18 @@ test('Create a form using the interactive builder', async ({ page, context }) =>
await formBuilderPage.renderingTypeDropdown().selectOption('radio');
});

await test.step('And then I type in the question label', async () => {
await formBuilderPage.questionLabelInput().fill(formDetails.pages[0].sections[0].questions[0].label);
});

await test.step('And then I set the question type to required', async () => {
await formBuilderPage.page
.getByRole('group', { name: /Is this question a required/i })
.locator('span')
.nth(2)
.click();
});

await test.step('And then I select the concept to be `Tested for COVID 19`', async () => {
await formBuilderPage.conceptSearchInput().fill('Tested for COVID 19');
await formBuilderPage.conceptSearchInput().press('Enter');
Expand All @@ -178,6 +180,7 @@ test('Create a form using the interactive builder', async ({ page, context }) =>
});

await test.step('And then I click on `Save`', async () => {
await expect(formBuilderPage.saveQuestionButton()).toBeEnabled();
await formBuilderPage.saveQuestionButton().click();
await expect(formBuilderPage.page.getByText(/new question created/i)).toBeVisible();
});
Expand Down
8 changes: 7 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ module.exports = {
'^.+\\.tsx?$': ['@swc/jest'],
},
transformIgnorePatterns: ['/node_modules/(?!@openmrs)'],
moduleDirectories: ['node_modules', '__mocks__', 'tools', 'src', __dirname],
moduleNameMapper: {
'^@resources/(.*)$': '<rootDir>/src/resources/$1',
'^@hooks/(.*)$': '<rootDir>/src/hooks/$1',
'^@types$': '<rootDir>/src/types.ts',
'^@tools/(.*)$': '<rootDir>/tools/$1',
'^@constants$': '<rootDir>/src/constants.ts',
'^@carbon/icons-react/es/(.*)$': '@carbon/icons-react/lib/$1',
'^carbon-components-react/es/(.*)$': 'carbon-components-react/lib/$1',
'@openmrs/esm-framework': '@openmrs/esm-framework/mock',
Expand All @@ -16,7 +22,7 @@ module.exports = {
'^react-i18next$': '<rootDir>/__mocks__/react-i18next.js',
'react-markdown': '<rootDir>/__mocks__/react-markdown.tsx',
},
setupFilesAfterEnv: ['<rootDir>/src/setup-tests.ts'],
setupFilesAfterEnv: ['<rootDir>/tools/setup-tests.ts'],
testEnvironment: 'jsdom',
testPathIgnorePatterns: ['<rootDir>/e2e'],
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"verify": "turbo run lint typescript coverage --color",
"coverage": "yarn test --coverage --passWithNoTests",
"postinstall": "husky install",
"extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.modal.tsx' --config ./i18next-parser.config.js",
"extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.modal.tsx' --config ./tools/i18next-parser.config.js",
"ci:bump-form-engine-lib": "yarn up @openmrs/esm-form-engine-lib@latest"
},
"files": [
Expand Down
13 changes: 6 additions & 7 deletions src/components/action-buttons/action-buttons.component.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import React, { useCallback, useState } from 'react';
import { Button, InlineLoading } from '@carbon/react';
import { useParams } from 'react-router-dom';
import { showModal, showSnackbar, useConfig } from '@openmrs/esm-framework';
import SaveFormModal from '../interactive-builder/modals/save-form/save-form.modal';
import { handleFormValidation } from '@resources/form-validator.resource';
import { publishForm, unpublishForm } from '@resources/forms.resource';
import { useForm } from '@hooks/useForm';
import type { IMarker } from 'react-ace';
import type { TFunction } from 'react-i18next';
import { showModal, showSnackbar, useConfig } from '@openmrs/esm-framework';

import { handleFormValidation } from '../../form-validator.resource';
import { publishForm, unpublishForm } from '../../forms.resource';
import { useForm } from '../../hooks/useForm';
import SaveFormModal from '../modals/save-form.modal';
import type { ConfigObject } from '../../config-schema';
import type { Schema } from '../../types';
import type { Schema } from '@types';
import styles from './action-buttons.scss';

interface ActionButtonsProps {
Expand Down
2 changes: 1 addition & 1 deletion src/components/audit-details/audit-details.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { useTranslation } from 'react-i18next';
import { formatDatetime, parseDate } from '@openmrs/esm-framework';
import { StructuredListWrapper, StructuredListRow, StructuredListCell, StructuredListBody } from '@carbon/react';
import type { EncounterType } from '../../types';
import type { EncounterType } from '@types';

interface AuditDetailsProps {
form: FormGroupData;
Expand Down
12 changes: 6 additions & 6 deletions src/components/dashboard/dashboard.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ import {
useLayoutType,
usePagination,
} from '@openmrs/esm-framework';
import type { ConfigObject } from '../../config-schema';
import type { Form as TypedForm } from '../../types';
import { deleteForm } from '../../forms.resource';
import { FormBuilderPagination } from '../pagination';
import { useClobdata } from '../../hooks/useClobdata';
import { useForms } from '../../hooks/useForms';
import EmptyState from '../empty-state/empty-state.component';
import ErrorState from '../error-state/error-state.component';
import Header from '../header/header.component';
import { deleteForm } from '@resources/forms.resource';
import { FormBuilderPagination } from '../pagination';
import { useClobdata } from '@hooks/useClobdata';
import { useForms } from '@hooks/useForms';
import type { ConfigObject } from '../../config-schema';
import type { Form as TypedForm } from '@types';
import styles from './dashboard.scss';

type Mutator = KeyedMutator<{
Expand Down
6 changes: 3 additions & 3 deletions src/components/dashboard/dashboard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React from 'react';
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { type FetchResponse, navigate, openmrsFetch, showModal } from '@openmrs/esm-framework';
import { renderWithSwr, waitForLoadingToFinish } from '../../test-helpers';
import { deleteForm } from '../../forms.resource';
import Dashboard from './dashboard.component';
import { renderWithSwr, waitForLoadingToFinish } from '@tools/test-helpers';
import { deleteForm } from '@resources/forms.resource';

type OpenmrsFetchResponse = Promise<
FetchResponse<{
Expand Down Expand Up @@ -38,7 +38,7 @@ const formsResponse = [
},
];

jest.mock('../../forms.resource', () => ({
jest.mock('@resources/forms.resource', () => ({
deleteForm: jest.fn(),
}));

Expand Down
14 changes: 7 additions & 7 deletions src/components/form-editor/form-editor.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ import { ArrowLeft, Maximize, Minimize, Download } from '@carbon/react/icons';
import { useParams } from 'react-router-dom';
import { type TFunction, useTranslation } from 'react-i18next';
import { ConfigurableLink, showModal, useConfig } from '@openmrs/esm-framework';
import type { IMarker } from 'react-ace';
import type { FormSchema } from '@openmrs/esm-form-engine-lib';
import type { Schema } from '../../types';
import { useClobdata } from '../../hooks/useClobdata';
import { useForm } from '../../hooks/useForm';
import { handleFormValidation } from '../../form-validator.resource';
import { type ConfigObject } from '../../config-schema';
import ActionButtons from '../action-buttons/action-buttons.component';
import AuditDetails from '../audit-details/audit-details.component';
import FormRenderer from '../form-renderer/form-renderer.component';
import Header from '../header/header.component';
import InteractiveBuilder from '../interactive-builder/interactive-builder.component';
import SchemaEditor from '../schema-editor/schema-editor.component';
import ValidationMessage from '../validation-info/validation-info.component';
import { handleFormValidation } from '@resources/form-validator.resource';
import { useClobdata } from '@hooks/useClobdata';
import { useForm } from '@hooks/useForm';
import type { IMarker } from 'react-ace';
import type { FormSchema } from '@openmrs/esm-form-engine-lib';
import type { Schema } from '@types';
import type { ConfigObject } from '../../config-schema';
import styles from './form-editor.scss';

interface ErrorProps {
Expand Down
Loading

0 comments on commit e5c6f76

Please sign in to comment.