Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[98] add query for curator comments #154

Merged
merged 16 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
13 changes: 12 additions & 1 deletion data-serving/scripts/setup-db/schemas/day0cases.indexes.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"location.admin2": "text",
"location.admin3": "text",
"caseReference.sourceUrl": "text",
"caseStatus": "text"
"caseStatus": "text",
"comment": "text"
}
},
{
Expand Down Expand Up @@ -145,6 +146,16 @@
"strength": 2
}
},
{
"name": "commentIdx",
"key": {
"comment": -1
},
"collation": {
"locale": "en_US",
"strength": 2
}
},
{
"name": "countryAndDate",
"key": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ describe('Linelist table', function () {
sourceUrl: 'www.example.com',
caseStatus: CaseStatus.Confirmed,
occupation: 'Actor',
comment: 'note',
});
cy.addCase({
country: 'Germany',
Expand All @@ -524,6 +525,7 @@ describe('Linelist table', function () {
cy.intercept('GET', getDefaultQuery({ limit: 50 })).as('getCases');
cy.intercept('GET', getDefaultQuery({ limit: 50, query: 'Argentina' })).as('getCasesWithSearch1');
cy.intercept('GET', getDefaultQuery({ limit: 50, query: 'Doctor' })).as('getCasesWithSearch2');
cy.intercept('GET', getDefaultQuery({ limit: 50, query: 'note' })).as('getCasesWithSearch3');

cy.visit('/cases');
cy.wait('@getCases');
Expand All @@ -549,5 +551,30 @@ describe('Linelist table', function () {
cy.contains('Argentina').should('not.exist');
cy.contains('France').should('not.exist');
cy.contains('Germany').should('exist');

cy.get('#clear-search').click();
cy.wait('@getCases');
cy.contains('Argentina').should('exist');
cy.contains('France').should('exist');
cy.contains('Germany').should('exist');

cy.get('#search-field').type('note');
cy.wait('@getCasesWithSearch3');
cy.contains('Argentina').should('not.exist');
cy.contains('France').should('exist');
cy.contains('Germany').should('not.exist');
});

it('Informs user when uneven number of quotes is present in free-text search', () => {
cy.intercept('GET', getDefaultQuery({ limit: 50, query: '"Bus driver"' })).as('getCasesWithSearch');
cy.visit('/cases');
cy.contains('Please make sure you have an even number of quotes.').should('not.exist');

cy.get('#search-field').type('"Bus driver');
cy.contains('Please make sure you have an even number of quotes.').should('exist');

cy.get('#search-field').type('"');
cy.wait('@getCasesWithSearch');
cy.contains('Please make sure you have an even number of quotes.').should('not.exist');
});
});
2 changes: 2 additions & 0 deletions verification/curator-service/ui/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ interface AddCaseProps {
gender?: Gender;
outcome?: Outcome;
uploadIds?: string[];
comment?: string;
}

declare global {
Expand Down Expand Up @@ -111,6 +112,7 @@ export function addCase(opts: AddCaseProps): void {
travelHistory: {},
genomeSequences: {},
vaccination: {},
comment: opts.comment || '',
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ export default function App(): JSX.Element {
)
return;

dispatch(setSearchQuery(location.search));
dispatch(setSearchQuery(decodeURI(location.search)));

// Save searchQuery to local storage not to lost it when user goes through auth process
localStorage.setItem('searchQuery', location.search);
Expand Down
55 changes: 44 additions & 11 deletions verification/curator-service/ui/src/components/DataGuideDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect } from 'react';
import { Box, Portal, Theme, Typography } from '@mui/material';
import { withStyles } from 'tss-react/mui';
import CloseIcon from '@mui/icons-material/Close';
import { Close as CloseIcon } from '@mui/icons-material';
import Draggable, { ControlPosition } from 'react-draggable';

// As per this issue from react-draggable library: https://github.com/react-grid-layout/react-draggable/pull/648
Expand Down Expand Up @@ -96,16 +96,49 @@ const SearchGuideDialog = ({
the left and choose ascending or descending.
</Typography>
<Typography className={classes?.textSection}>
<strong>For full-text search</strong>, enter any combination of search terms.
<br/>
Full-text search covers: occupation, admin0, admin1, admin2, admin3, sourceUrl and caseStatus.
<br/>
Search terms must be exact (example: "German" will not match "Germany").
<br/>
Full-text search matches cases that contain any ot the search terms, not a combination.
<br/>
No special characters apart from "." are allowed and if the "." is used in a search term
given search term must be contained within quotation marks.
<strong>For full-text search</strong>, enter any
combination of search terms. Rules for full-text
search:
<br />
<ul>
<li>
Full-text search covers: occupation, admin0,
admin1, admin2, admin3, sourceUrl, comment
and caseStatus.
</li>
<li>
Search terms must be exact (example:{' '}
<b>
<i>German</i>
</b>{' '}
will not match{' '}
<b>
<i>Germany</i>
</b>
).
</li>
<li>
Full-text search matches cases that contain
any of the search terms, not a combination.
</li>
<li>
To search for a combination of terms, wrap
the combination in quotation marks (example:{' '}
<b>
<i>"Bus driver"</i>
</b>
).
</li>
<li>
No special characters apart from dot are
allowed. Search terms with dot must be
contained within quotation marks (example:{' '}
<b>
<i>"global.health"</i>
</b>
).
</li>
</ul>
</Typography>
<Typography>
You can use the icons on the right to navigate
Expand Down
16 changes: 12 additions & 4 deletions verification/curator-service/ui/src/components/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,24 @@ export default function SearchBar({
return searchStringStrippedOutColon;
}

const renderSearchErrorMessage = () => {
if (searchError) {
return 'Incorrect entry. ":" characters have been removed. Please use filters instead.';
} else {
const quoteCount = decodeURI(searchInput).split('"').length - 1;
if (quoteCount % 2 !== 0) {
return 'Incorrect entry. Please make sure you have an even number of quotes.';
}
}
};

return (
<>
<div className={classes.searchRoot}>
<StyledSearchTextField
size="small"
error={searchError}
helperText={
searchError &&
'Incorrect entry. ":" characters have been removed. Please use filters instead.'
}
helperText={renderSearchErrorMessage()}
id="search-field"
data-testid="searchbar"
name="searchbar"
Expand Down
33 changes: 26 additions & 7 deletions verification/curator-service/ui/src/components/ViewCase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -966,16 +966,35 @@ function RowContent(props: {
linkComment?: string;
}): JSX.Element {
const searchQuery = useSelector(selectSearchQuery);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const searchQueryArray: any[] = [];
const searchQueryArray: string[] = [];

function words(s: string) {
const regex = /"([^"]+)"|(\w{3,})/g;
let match;
while ((match = regex.exec(s))) {
searchQueryArray.push(match[match[1] ? 1 : 2]);
if (s.startsWith('?q=')) s = s.substring(3);

const quoted: string[] = [];
const notQuoted: string[] = [];
if (s.includes('"') && s.replace(/[^"]/g, '').length % 2 !== 1) {
s.split('"').map((subs: string, i: number) => {
subs != '' && i % 2 ? quoted.push(subs) : notQuoted.push(subs);
});
} else notQuoted.push(s);

const regex = /"([^"]+)"|(\w{1,})/g;
// Make sure that terms in quotes will be highlighted as one search term
for (const quotedEntry of quoted) {
let match;
let accumulator: string[] = [];
while ((match = regex.exec(quotedEntry))) {
accumulator.push(match[match[1] ? 1 : 2]);
}
searchQueryArray.push(accumulator.join(' '));
}
for (const notQuotedEntry of notQuoted) {
let match;
while ((match = regex.exec(notQuotedEntry))) {
searchQueryArray.push(match[match[1] ? 1 : 2]);
}
}
return searchQueryArray;
}
words(searchQuery);

Expand Down
Loading