Skip to content

Commit

Permalink
(feat) Implement fuzzy search in the forms dashboard (openmrs#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
denniskigen committed Oct 30, 2023
1 parent f1308e8 commit 51ed50c
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 39 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@openmrs/openmrs-form-engine-lib": "next",
"dotenv": "^16.3.1",
"file-loader": "^6.2.0",
"fuzzy": "^0.1.3",
"lodash-es": "^4.17.21",
"react-ace": "^10.1.0",
"sass": "^1.67.0"
Expand Down
64 changes: 25 additions & 39 deletions src/components/dashboard/dashboard.component.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useCallback, useMemo, useState } from 'react';
import fuzzy from 'fuzzy';
import type { TFunction } from 'i18next';
import { useTranslation } from 'react-i18next';
import {
Expand Down Expand Up @@ -35,10 +36,11 @@ import {
useConfig,
useLayoutType,
usePagination,
useDebounce,
} from '@openmrs/esm-framework';
import type { KeyedMutator } from 'swr';

import type { Form as FormType } from '../../types';
import type { Form as TypedForm } from '../../types';
import { deleteForm } from '../../forms.resource';
import { FormBuilderPagination } from '../pagination';
import { useClobdata } from '../../hooks/useClobdata';
Expand All @@ -49,19 +51,19 @@ import styles from './dashboard.scss';

type Mutator = KeyedMutator<{
data: {
results: Array<FormType>;
results: Array<TypedForm>;
};
}>;

interface ActionButtonsProps {
form: FormType;
form: TypedForm;
mutate: Mutator;
responsiveSize: string;
t: TFunction;
}

interface FormsListProps {
forms: Array<FormType>;
forms: Array<TypedForm>;
isValidating: boolean;
mutate: Mutator;
t: TFunction;
Expand Down Expand Up @@ -245,28 +247,28 @@ function ActionButtons({ form, mutate, responsiveSize, t }: ActionButtonsProps)
}

function FormsList({ forms, isValidating, mutate, t }: FormsListProps) {
const pageSize = 10;
const config = useConfig();
const isTablet = useLayoutType() === 'tablet';
const responsiveSize = isTablet ? 'lg' : 'sm';
const [filter, setFilter] = useState('');
const [searchString, setSearchString] = useState('');
const pageSize = 10;
const [, setFilter] = useState('');
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearchTerm = useDebounce(searchTerm);

const filteredRows = useMemo(() => {
if (!filter) {
const filteredForms = useMemo(() => {
if (!debouncedSearchTerm) {
return forms;
}

if (filter === 'Published') {
return forms.filter((form) => form.published);
}

if (filter === 'Unpublished') {
return forms.filter((form) => !form.published);
}

return forms;
}, [filter, forms]);
return debouncedSearchTerm
? fuzzy
.filter(debouncedSearchTerm, forms, {
extract: (form: TypedForm) => `${form.name} ${form.version}`,
})
.sort((r1, r2) => r1.score - r2.score)
.map((result) => result.original)
: forms;
}, [forms, debouncedSearchTerm]);

const tableHeaders = [
{
Expand All @@ -291,17 +293,9 @@ function FormsList({ forms, isValidating, mutate, t }: FormsListProps) {
},
];

const searchResults = useMemo(() => {
if (searchString && searchString.trim() !== '') {
return filteredRows.filter((form) => form.name.toLowerCase().includes(searchString.toLowerCase()));
}

return filteredRows;
}, [searchString, filteredRows]);

const { paginated, goTo, results, currentPage } = usePagination(searchResults, pageSize);
const { paginated, goTo, results, currentPage } = usePagination(filteredForms, pageSize);

const tableRows = results?.map((form: FormType) => ({
const tableRows = results?.map((form: TypedForm) => ({
...form,
id: form?.uuid,
published: <CustomTag condition={form.published} />,
Expand All @@ -311,14 +305,6 @@ function FormsList({ forms, isValidating, mutate, t }: FormsListProps) {

const handlePublishStatusChange = ({ selectedItem }: { selectedItem: string }) => setFilter(selectedItem);

const handleSearch = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
goTo(1);
setSearchString(e.target.value);
},
[goTo, setSearchString],
);

return (
<>
{config.showSchemaSaveWarning && (
Expand Down Expand Up @@ -358,7 +344,7 @@ function FormsList({ forms, isValidating, mutate, t }: FormsListProps) {
<TableToolbarContent className={styles.headerContainer}>
<TableToolbarSearch
className={styles.searchbox}
onChange={handleSearch}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSearchTerm(e.target.value)}
placeholder={t('searchThisList', 'Search this list')}
/>
<Button
Expand Down Expand Up @@ -412,7 +398,7 @@ function FormsList({ forms, isValidating, mutate, t }: FormsListProps) {
{paginated && (
<FormBuilderPagination
currentItems={results.length}
totalItems={searchResults.length}
totalItems={filteredForms.length}
onPageNumberChange={({ page }) => {
goTo(page);
}}
Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3293,6 +3293,7 @@ __metadata:
eslint-plugin-playwright: ^0.16.0
eslint-plugin-prettier: ^5.0.0
file-loader: ^6.2.0
fuzzy: ^0.1.3
husky: ^8.0.3
i18next: ^23.5.1
i18next-parser: ^8.7.0
Expand Down Expand Up @@ -10575,6 +10576,13 @@ __metadata:
languageName: node
linkType: hard

"fuzzy@npm:^0.1.3":
version: 0.1.3
resolution: "fuzzy@npm:0.1.3"
checksum: acc09c6173e12d5dc8ae51857551ddbe834befa9ebc6be6d5581d09117265d704809d80407d220fd0652f347a9975a4d106854cacc8bd031487a0ede86982f84
languageName: node
linkType: hard

"gauge@npm:^4.0.3":
version: 4.0.4
resolution: "gauge@npm:4.0.4"
Expand Down

0 comments on commit 51ed50c

Please sign in to comment.