Skip to content

Commit

Permalink
feat(tags): Ignore tags of 2 or less characters
Browse files Browse the repository at this point in the history
  • Loading branch information
annelhote committed Mar 20, 2024
1 parent 16a2ab6 commit 15573a1
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 34 deletions.
1 change: 1 addition & 0 deletions client/.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
VITE_API=/api
VITE_APP_MATOMO_BASE_URL=https://matomo.staging.dataesr.ovh
VITE_APP_NAME="Works magnet 🧲"
VITE_APP_TAG_LIMIT=3
VITE_DESCRIPTION="Retrieve the scholarly works of your institution"
VITE_GIT_REPOSITORY_URL="https://github.com/dataesr/works-magnet"
VITE_HEADER_TAG=dev
Expand Down
56 changes: 36 additions & 20 deletions client/src/components/tag-input/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,52 @@ import { Button, Col, Icon, Row, Tag, TagGroup, TextInput } from '@dataesr/react
import PropTypes from 'prop-types';
import { useEffect, useState } from 'react';

const { VITE_APP_TAG_LIMIT } = import.meta.env;

const SEE_MORE_AFTER = 5;

export default function TagInput({
deletedTags,
getRoRChildren,
hint,
label,
message,
messageType,
onInputHandler,
onTagsChange,
placeholder,
tags,
getRoRChildren,
setGetRoRChildren,
deletedTags,
tags,
}) {
const [excludedValues, setExcludedValues] = useState(deletedTags);
const [input, setInput] = useState('');
const [seeMore, setSeeMore] = useState(false);
const [values, setValues] = useState(tags);

const getTagColor = (tag) => {
if (tag.disable) return 'beige-gris-galet';
if (tag.source === 'ror') return 'brown-caramel';
return 'brown-cafe-creme';
};

const handleDeleteClick = (tag) => {
const deletedValues = excludedValues;
deletedValues.push(tag);
const newValues = [...values.filter((el) => el !== tag)];
setValues(newValues);
setExcludedValues(deletedValues);
onTagsChange(newValues, deletedValues);
};

const handleKeyDown = (e) => {
if ([9, 13].includes(e.keyCode) && input) {
e.preventDefault();
if (values.map((value) => value.label).includes(input.trim())) {
setInput('');
return;
}
const newValues = [...values, { label: input.trim(), source: 'user' }];
const inputLabel = input.trim();
const newValues = [...values, { disable: inputLabel.length < VITE_APP_TAG_LIMIT, label: inputLabel, source: 'user' }];
setValues(newValues);
setInput('');
onTagsChange(newValues, excludedValues);
Expand All @@ -44,18 +62,10 @@ export default function TagInput({
}
}, [input, onInputHandler]);

const handleDeleteClick = (tag) => {
const deletedValues = excludedValues;
deletedValues.push(tag);
const newValues = [...values.filter((el) => el !== tag)];
setValues(newValues);
setExcludedValues(deletedValues);
onTagsChange(newValues, deletedValues);
};

useEffect(() => setValues(tags), [tags]);

useEffect(() => setExcludedValues(deletedTags), [deletedTags]);

let hasRoR = false;
let newLine = [];
const structuredTags = [];
Expand All @@ -72,6 +82,7 @@ export default function TagInput({
if (newLine.length) {
structuredTags.push(newLine);
}

return (
<div>
<div>
Expand Down Expand Up @@ -99,10 +110,11 @@ export default function TagInput({
{currentTags.map((tag) => (
<Tag
className="fr-mr-1w"
small
colorFamily={(tag?.source ?? 'user') === 'user' ? 'brown-cafe-creme' : 'brown-caramel'}
colorFamily={getTagColor(tag)}
key={tag.label}
onClick={() => handleDeleteClick(tag)}
size="sm"
title={`Tag ${tag.label}${tag.disable ? ' (not searched)' : ''}`}
>
{tag.label}
<Icon iconPosition="right" name="ri-close-line" />
Expand All @@ -111,10 +123,10 @@ export default function TagInput({
{(index === 0 && hasRoR) ? (
<Button
className="fr-mr-1w"
onClick={() => setGetRoRChildren((prev) => !prev)}
size="sm"
hasBorder={false}
icon={getRoRChildren ? 'ri-arrow-go-back-line' : 'ri-node-tree'}
onClick={() => setGetRoRChildren((prev) => !prev)}
size="sm"
>
{
getRoRChildren
Expand Down Expand Up @@ -153,23 +165,27 @@ export default function TagInput({
}

TagInput.propTypes = {
deletedTags: PropTypes.arrayOf(PropTypes.object),
getRoRChildren: PropTypes.bool,
hint: PropTypes.string,
label: PropTypes.string.isRequired,
message: PropTypes.string,
messageType: PropTypes.oneOf(['error', 'valid', '']),
onInputHandler: PropTypes.func,
onTagsChange: PropTypes.func.isRequired,
placeholder: PropTypes.string,
setGetRoRChildren: PropTypes.func,
tags: PropTypes.arrayOf(PropTypes.object),
deletedTags: PropTypes.arrayOf(PropTypes.object),
};

TagInput.defaultProps = {
hint: 'Valider votre ajout avec la touche "Entrée"',
deletedTags: [],
getRoRChildren: false,
hint: 'Press "ENTER" to search for several terms',
message: '',
messageType: '',
onInputHandler: () => { },
placeholder: '',
setGetRoRChildren: () => {},
tags: [],
deletedTags: [],
};
34 changes: 21 additions & 13 deletions client/src/pages/filters.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { useSearchParams } from 'react-router-dom';
import TagInput from '../components/tag-input';
import { getRorData, isRor } from '../utils/ror';

const { VITE_APP_TAG_LIMIT } = import.meta.env;

const START_YEAR = 2010;
const years = [...Array(new Date().getFullYear() - START_YEAR + 1).keys()].map((year) => (year + START_YEAR).toString()).map((year) => ({ label: year, value: year }));

Expand Down Expand Up @@ -56,24 +58,25 @@ export default function Filters({ sendQuery }) {
setMessage('');
affiliations.forEach((affiliation) => {
if (isRor(affiliation)) {
allTags.push({ label: affiliation.replace('https://ror.org/', '').replace('ror.org/', ''), source: 'user', type: 'rorId' });
const label = affiliation.replace('https://ror.org/', '').replace('ror.org/', '');
allTags.push({ disable: label.length < VITE_APP_TAG_LIMIT, label, source: 'user', type: 'rorId' });
} else {
allTags.push({ label: affiliation, source: 'user', type: 'affiliationString' });
allTags.push({ disable: affiliation.length < VITE_APP_TAG_LIMIT, label: affiliation, source: 'user', type: 'affiliationString' });
}
knownTags[affiliation.toLowerCase()] = 1;
});
rorNames.flat().forEach((rorElt) => {
if (knownTags[rorElt.rorId.toLowerCase()] === undefined) {
if (!deletedAffiliations.includes(rorElt.rorId)) {
allTags.push({ label: rorElt.rorId, source: 'ror', type: 'rorId' });
allTags.push({ disable: rorElt.rorId.length < VITE_APP_TAG_LIMIT, label: rorElt.rorId, source: 'ror', type: 'rorId' });
knownTags[rorElt.rorId.toLowerCase()] = 1;
}
}
rorElt.names.forEach((rorName) => {
if (knownTags[rorName.toLowerCase()] === undefined) {
if (!deletedAffiliations.includes(rorName)) {
const isDangerous = rorName.length < 4;
allTags.push({ label: rorName, source: 'ror', type: 'affiliationString', rorId: rorElt.rorId, isDangerous });
allTags.push({ disable: rorName.length < VITE_APP_TAG_LIMIT, label: rorName, source: 'ror', type: 'affiliationString', rorId: rorElt.rorId, isDangerous });
knownTags[rorName.toLowerCase()] = 1;
}
}
Expand Down Expand Up @@ -107,10 +110,15 @@ export default function Filters({ sendQuery }) {
}
setMessageType('');
setMessage('');
const queryParams = { datasets: currentSearchParams.datasets, startYear: currentSearchParams.startYear, endYear: currentSearchParams.endYear };
const queryParams = { ...currentSearchParams };
// TO REVIEW
queryParams.affiliationStrings = tags.filter((tag) => tag.type === 'affiliationString').map((tag) => normalizeStr(tag.label)).slice(0, 100);
queryParams.rors = tags.filter((tag) => tag.type === 'rorId').map((tag) => tag.label).slice(0, 100);
queryParams.affiliationStrings = tags.filter((tag) => !tag.disable && tag.type === 'affiliationString').map((tag) => normalizeStr(tag.label)).slice(0, 100);
queryParams.rors = tags.filter((tag) => !tag.disable && tag.type === 'rorId').map((tag) => tag.label).slice(0, 100);
if (queryParams.affiliationStrings.length === 0 && queryParams.rors.length === 0) {
setMessageType('error');
setMessage(`You must provide at least one affiliation longer than ${VITE_APP_TAG_LIMIT} letters.`);
return;
}
sendQuery(queryParams);
};

Expand All @@ -119,26 +127,26 @@ export default function Filters({ sendQuery }) {
<Col n="2">
<Select
label="Start year"
onChange={(e) => setSearchParams({ ...currentSearchParams, startYear: e.target.value })}
options={years}
selected={currentSearchParams.startYear}
onChange={(e) => setSearchParams({ ...currentSearchParams, startYear: e.target.value })}
/>
</Col>
<Col n="2">
<Select
label="End year"
onChange={(e) => setSearchParams({ ...currentSearchParams, endYear: e.target.value })}
options={years}
selected={currentSearchParams.endYear}
onChange={(e) => setSearchParams({ ...currentSearchParams, endYear: e.target.value })}
/>
</Col>
<Col n="3">
<CheckboxGroup
legend="&nbsp;"
>
<Checkbox
label="Search for datasets only"
checked={currentSearchParams?.datasets ?? false}
label="Search for datasets only"
onChange={(e) => setSearchParams({ ...currentSearchParams, datasets: e.target.checked })}
/>
</CheckboxGroup>
Expand All @@ -153,15 +161,15 @@ export default function Filters({ sendQuery }) {
</Col>
<Col n="12">
<TagInput
getRoRChildren={getRoRChildren}
hint="Press ENTER to search for several terms / expressions. If several, an OR operator is used."
label="Affiliation name, RoR identifier"
message={message}
messageType={messageType}
onInputHandler={setOnInputAffiliationsHandler}
onTagsChange={onTagsChange}
tags={tags}
getRoRChildren={getRoRChildren}
setGetRoRChildren={setGetRoRChildren}
onInputHandler={setOnInputAffiliationsHandler}
tags={tags}
/>
</Col>
</Row>
Expand Down
3 changes: 2 additions & 1 deletion client/src/styles/index.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.text-right {
text-align: right;
text-align: right;
}

.fr-tags-group>li {
line-height: 0rem;
}

0 comments on commit 15573a1

Please sign in to comment.