Skip to content

Commit

Permalink
(chore) Various tooling tweaks
Browse files Browse the repository at this point in the history
This commit includes the following changes to the tooling used in this project:

- Update ESLint config with `import` and `react-hooks` plugins
- Add turborepo for build caching and script parallelization
- Align TypeScript and Jest configs with OpenMRS standards
- Separate linting from formatting scripts so they can be run separately as described in [similar PRs](openmrs/openmrs-esm-patient-chart#1774) for other OpenMRS frontend modules
- Update Yarn to latest stable version
- Remove redundant Webpack `scriptRuleConfig` override

This aligns our tooling configuration with other OpenMRS frontend modules, improving consistency across the ecosystem.
  • Loading branch information
denniskigen committed Dec 4, 2024
1 parent 149aba1 commit 88a4db4
Show file tree
Hide file tree
Showing 58 changed files with 2,632 additions and 1,983 deletions.
73 changes: 66 additions & 7 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,11 +1,70 @@
{
"env": {
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "import", "unused-imports"],
"rules": {
"unused-imports/no-unused-imports": "error",
"react-hooks/exhaustive-deps": 0,
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unused-vars": "error"
"parserOptions": {
"project": true,
"tsconfigRootDir": "__dirname"
},
"extends": ["ts-react-important-stuff", "plugin:prettier/recommended"]
"plugins": ["@typescript-eslint", "import", "react-hooks", "unused-imports"],
"root": true,
"rules": {
// 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/ban-types": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unsafe-return": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/unbound-method": "off",
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/consistent-type-exports": "error",
// Use `import type` instead of `import` for type imports
"@typescript-eslint/consistent-type-imports": [
"error",
{
"fixStyle": "inline-type-imports"
}
],
"import/no-duplicates": "error",
"no-console": ["error", { "allow": ["warn", "error"] }],
"no-restricted-imports": [
"error",
{
"paths": [
// These two rules ensure that we're importing lodash and lodash-es correctly. Not doing so can bloat our bundle size significantly.
{
"name": "lodash",
"message": "Import specific methods from `lodash`. e.g. `import map from 'lodash/map'`"
},
{
"name": "lodash-es",
"importNames": ["default"],
"message": "Import specific methods from `lodash-es`. e.g. `import { map } from 'lodash-es'`"
},
// These two rules ensure that we're importing Carbon components and icons from the correct packages (after v10). May be removed in the future.
{
"name": "carbon-components-react",
"message": "Import from `@carbon/react` directly. e.g. `import { Toggle } from '@carbon/react'`"
},
{
"name": "@carbon/icons-react",
"message": "Import from `@carbon/react/icons`. e.g. `import { ChevronUp } from '@carbon/react/icons'`"
}
]
}
],
"unused-imports/no-unused-imports-ts": "error",
"react-hooks/exhaustive-deps": "warn",
"react-hooks/rules-of-hooks": "error"
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,5 @@ dist/
/playwright-report/
/playwright/.cache/
e2e/storageState.json

.turbo
894 changes: 0 additions & 894 deletions .yarn/releases/yarn-4.2.2.cjs

This file was deleted.

934 changes: 934 additions & 0 deletions .yarn/releases/yarn-4.5.3.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ enableGlobalCache: false

nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-4.2.2.cjs
yarnPath: .yarn/releases/yarn-4.5.3.cjs
4 changes: 3 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
module.exports = {
clearMocks: true,
transform: {
"^.+\\.tsx?$": "@swc/jest",
},
transformIgnorePatterns: ["/node_modules/(?!@openmrs)"],
moduleNameMapper: {
"\\.(s?css)$": "identity-obj-proxy",
"@openmrs/esm-framework": "@openmrs/esm-framework/mock",
"^dexie$": require.resolve("dexie"),
"^lodash-es/(.*)$": "lodash/$1",
"^lodash-es$": "lodash",
"^uuid$": "<rootDir>/node_modules/uuid/dist/index.js",
"^dexie$": require.resolve("dexie"),
},
setupFilesAfterEnv: ["<rootDir>/src/setup-tests.ts"],
testEnvironment: "jsdom",
Expand Down
32 changes: 18 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@openmrs/esm-cohort-builder-app",
"version": "4.0.0",
"license": "MPL-2.0",
"description": "A microfrontend for OpenMRS cohorts",
"description": "O3 frontend module for managing cohorts",
"browser": "dist/openmrs-esm-cohort-builder-app.js",
"main": "src/index.ts",
"source": true,
Expand All @@ -15,6 +15,7 @@
"prettier": "prettier --write \"src/**/*.{ts,tsx}\"",
"typescript": "tsc",
"test": "jest --config jest.config.js --verbose",
"test:watch": "jest --config jest.config.js --watch",
"test-e2e": "playwright test",
"verify": "concurrently 'yarn:lint' 'yarn:test' 'yarn:typescript'",
"coverage": "yarn test -- --coverage",
Expand Down Expand Up @@ -53,6 +54,10 @@
"react-dom": "18.x",
"react-i18next": "11.x"
},
"dependencies": {
"classnames": "^2.3.2",
"dotenv": "^16.3.1"
},
"devDependencies": {
"@carbon/react": "1.21.0",
"@openmrs/esm-framework": "next",
Expand All @@ -70,36 +75,35 @@
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@types/webpack-env": "^1.18.0",
"@typescript-eslint/eslint-plugin": "^5.51.0",
"@typescript-eslint/parser": "^5.51.0",
"@typescript-eslint/eslint-plugin": "^7.9.0",
"@typescript-eslint/parser": "^7.9.0",
"concurrently": "^7.6.0",
"css-loader": "^6.7.3",
"dayjs": "^1.11.7",
"eslint": "^8.33.0",
"eslint-config-prettier": "^8.6.0",
"eslint-config-ts-react-important-stuff": "^3.0.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-prettier": "^4.2.1",
"eslint": "^8.50.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-unused-imports": "^2.0.0",
"husky": "^8.0.3",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.4.2",
"jest-cli": "^29.4.2",
"jest-environment-jsdom": "^29.4.2",
"lint-staged": "^15.2.10",
"openmrs": "next",
"prettier": "^2.8.4",
"pretty-quick": "^3.1.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^12.1.5",
"swc-loader": "^0.2.3",
"turbo": "^2.3.3",
"typescript": "^4.9.5",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1"
},
"packageManager": "[email protected]",
"dependencies": {
"classnames": "^2.3.2",
"dotenv": "^16.3.1"
}
"lint-staged": {
"*.{ts,tsx}": "eslint --cache --fix --max-warnings 0",
"*.{css,scss,ts,tsx}": "prettier --write --list-different"
},
"packageManager": "[email protected]"
}
13 changes: 6 additions & 7 deletions src/cohort-builder.resources.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import useSWRImmutable from "swr/immutable";
import {
openmrsFetch,
FetchResponse,
restBaseUrl,
type FetchResponse,
} from "@openmrs/esm-framework";
import useSWRImmutable from "swr/immutable";

import { Patient, SearchParams, DropdownValue, Response } from "./types";
import type { Patient, SearchParams, DropdownValue, Response } from "./types";

/**
* @param searchParams query details
Expand All @@ -22,7 +21,7 @@ export const search = async (searchParams: SearchParams) => {
method: "POST",
headers: { "Content-Type": "application/json" },
body: searchParams.query,
}
},
);
return searchResults;
};
Expand Down Expand Up @@ -56,7 +55,7 @@ export const getDataSet = async (queryID: string) => {
`${restBaseUrl}/reportingrest/dataSet/${queryID}`,
{
method: "GET",
}
},
);

const dataset = results.data.rows.map((patient: Patient) => {
Expand All @@ -74,7 +73,7 @@ export const getCohortMembers = async (cohortId: string) => {
`${restBaseUrl}/cohort/${cohortId}/member?v=full`,
{
method: "GET",
}
},
);

const dataset = results.data.rows.map((patient: Patient) => {
Expand Down
5 changes: 1 addition & 4 deletions src/cohort-builder.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import React from "react";

import { render, cleanup } from "@testing-library/react";

import { render } from "@testing-library/react";
import CohortBuilder from "./cohort-builder";

describe("Test the cohort builder", () => {
afterEach(cleanup);
it(`renders without dying`, () => {
render(<CohortBuilder />);
});
Expand Down
76 changes: 37 additions & 39 deletions src/cohort-builder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import classNames from "classnames";
import { Tab, Tabs, TabList, TabPanels, TabPanel } from "@carbon/react";
import { showToast, useLayoutType } from "@openmrs/esm-framework";
import { useTranslation } from "react-i18next";

import {
getCohortMembers,
getDataSet,
search,
} from "./cohort-builder.resources";
import styles from "./cohort-builder.scss";
import { addToHistory } from "./cohort-builder.utils";
import { type Patient, type SearchParams } from "./types";
import Composition from "./components/composition/composition.component";
import SavedCohorts from "./components/saved-cohorts/saved-cohorts.component";
import SavedQueries from "./components/saved-queries/saved-queries.component";
Expand All @@ -23,7 +22,7 @@ import SearchByLocation from "./components/search-by-location/search-by-location
import SearchByPersonAttributes from "./components/search-by-person-attributes/search-by-person-attributes.component";
import SearchHistory from "./components/search-history/search-history.component";
import SearchResultsTable from "./components/search-results-table/search-results-table.component";
import { Patient, SearchParams } from "./types";
import styles from "./cohort-builder.scss";

interface TabItem {
name: string;
Expand All @@ -38,41 +37,40 @@ const CohortBuilder: React.FC = () => {

const runSearch = (
searchParams: SearchParams,
queryDescription: string
queryDescription: string,
): Promise<boolean> => {
return new Promise(async (resolve) => {
return new Promise((resolve) => {
setPatients([]);
try {
const {
data: { rows },
} = await search(searchParams);
rows.map((patient: Patient) => {
patient.id = patient.patientId.toString();
patient.name = `${patient.firstname} ${patient.lastname}`;
});
setPatients(rows);
addToHistory(queryDescription, rows, searchParams.query);
showToast({
title: t("success", "Success!"),
kind: "success",
critical: true,
description: t(
"searchIsCompleted",
`Search is completed with ${rows.length} result(s)`,
{ numOfResults: rows.length }
),
});
setIsHistoryUpdated(true);
resolve(true);
} catch (error) {
showToast({
title: t("error", "Error"),
kind: "error",
critical: true,
description: error?.message,
search(searchParams)
.then(({ data: { rows } }) => {
rows.map((patient: Patient) => {
patient.id = patient.patientId.toString();
patient.name = `${patient.firstname} ${patient.lastname}`;
});
setPatients(rows);
addToHistory(queryDescription, rows, searchParams.query);
showToast({
title: t("success", "Success!"),
kind: "success",
critical: true,
description: t(
"searchIsCompleted",
`Search is completed with ${rows.length} result(s)`,
{ numOfResults: rows.length },
),
});
setIsHistoryUpdated(true);
resolve(true);
})
.catch((error) => {
showToast({
title: t("error", "Error"),
kind: "error",
critical: true,
description: error?.message,
});
resolve(true);
});
resolve(true);
}
});
};

Expand All @@ -87,7 +85,7 @@ const CohortBuilder: React.FC = () => {
description: t(
"searchIsCompleted",
`Search is completed with ${patients.length} result(s)`,
{ numOfResults: patients.length }
{ numOfResults: patients.length },
),
});
} catch (error) {
Expand All @@ -111,7 +109,7 @@ const CohortBuilder: React.FC = () => {
description: t(
"searchIsCompleted",
`Search is completed with ${patients.length} result(s)`,
{ numOfResults: patients.length }
{ numOfResults: patients.length },
),
});
} catch (error) {
Expand Down Expand Up @@ -172,12 +170,12 @@ const CohortBuilder: React.FC = () => {
className={classNames(
"omrs-main-content",
styles.mainContainer,
styles.cohortBuilder
styles.cohortBuilder,
)}
>
<div
className={classNames(
isLayoutTablet ? styles.tabletContainer : styles.desktopContainer
isLayoutTablet ? styles.tabletContainer : styles.desktopContainer,
)}
>
<p className={styles.title}>{t("cohortBuilder", "Cohort Builder")}</p>
Expand Down
Loading

0 comments on commit 88a4db4

Please sign in to comment.