Skip to content

Commit

Permalink
Merge pull request #3209 from ingef/allow-inserting-unknown-filter-va…
Browse files Browse the repository at this point in the history
…lues

Allow inserting unknown filter values
  • Loading branch information
Kadrian authored Nov 13, 2023
2 parents 978f3c0 + df14558 commit 53b2d3c
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 144 deletions.
48 changes: 38 additions & 10 deletions frontend/src/js/query-node-editor/FilterListMultiSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,13 @@ const FilterListMultiSelect: FC<PropsT> = ({

try {
const r = await postFilterValuesResolve(filterId, rows);
const hasUnknownCodes = r.unknownCodes && r.unknownCodes.length > 0;

setResolved(r);
setIsModalOpen(!!r.unknownCodes && r.unknownCodes.length > 0);

if (
r.resolvedFilter &&
r.resolvedFilter.value &&
r.resolvedFilter.value.length > 0
) {
onChange(r.resolvedFilter.value);
if (hasUnknownCodes) {
setResolved(r);
setIsModalOpen(true);
} else {
onSubmitResolvedValues(r, { includeUnresolved: false });
}
} catch (e) {
setError(true);
Expand All @@ -148,13 +145,44 @@ const FilterListMultiSelect: FC<PropsT> = ({
setLoading(false);
};

const onSubmitResolvedValues = (
resolvedResponse: PostFilterResolveResponseT,
{
includeUnresolved,
}: {
includeUnresolved?: boolean;
},
) => {
const hasSomethingToInsert =
(resolvedResponse.resolvedFilter?.value?.length || 0) > 0 ||
resolvedResponse.unknownCodes.length > 0;

console.log("hasSomethingToInsert", hasSomethingToInsert);
console.log("resolvedResponse", resolvedResponse);

if (!hasSomethingToInsert) return;

const value = includeUnresolved
? [
...resolvedResponse.resolvedFilter!.value,
...resolvedResponse.unknownCodes.map((item) => ({
label: item,
value: item,
})),
]
: resolvedResponse.resolvedFilter!.value;

onChange(value);
};

return (
<>
{allowDropFile && isModalOpen && (
{allowDropFile && isModalOpen && resolved && (
<UploadFilterListModal
resolved={resolved}
loading={loading}
error={error}
onSubmit={onSubmitResolvedValues}
onClose={() => setIsModalOpen(false)}
/>
)}
Expand Down
119 changes: 76 additions & 43 deletions frontend/src/js/query-node-editor/UploadFilterListModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,36 @@ import {
faExclamationCircle,
faSpinner,
} from "@fortawesome/free-solid-svg-icons";
import { FC } from "react";
import { useTranslation } from "react-i18next";

import { useState } from "react";
import type { PostFilterResolveResponseT } from "../api/types";
import PrimaryButton from "../button/PrimaryButton";
import FaIcon from "../icon/FaIcon";
import Modal from "../modal/Modal";
import ScrollableList from "../scrollable-list/ScrollableList";
import InputCheckbox from "../ui-components/InputCheckbox";

const Root = styled("div")`
padding: 0 0 10px;
display: flex;
flex-direction: column;
gap: 15px;
`;
const Section = styled("div")`
padding: 10px 20px;
const Col = styled("div")`
display: flex;
flex-direction: column;
gap: 5px;
`;

const Msg = styled("p")`
margin: 10px 0 5px;
margin: 0;
display: flex;
align-items: center;
gap: 10px;
`;
const BigIcon = styled(FaIcon)`
font-size: 20px;
margin-right: 10px;
`;
const ErrorIcon = styled(BigIcon)`
color: ${({ theme }) => theme.col.red};
Expand All @@ -35,13 +45,6 @@ const CenteredIcon = styled(FaIcon)`
text-align: center;
`;

interface PropsT {
loading: boolean;
resolved: PostFilterResolveResponseT | null;
error: boolean;
onClose: () => void;
}

const selectResolvedItemsCount = (
resolved: PostFilterResolveResponseT | null,
) => {
Expand All @@ -56,19 +59,35 @@ const selectUnresolvedItemsCount = (
: 0;
};

const UploadFilterListModal: FC<PropsT> = ({
const UploadFilterListModal = ({
loading,
resolved,
error,
onSubmit,
onClose,
}: {
loading: boolean;
resolved: PostFilterResolveResponseT;
error: boolean;
onSubmit: (
resolved: PostFilterResolveResponseT,
{ includeUnresolved }: { includeUnresolved: boolean },
) => void;
onClose: () => void;
}) => {
const { t } = useTranslation();
const [includeUnresolved, setIncludeUnresolved] = useState(false);

const resolvedItemsCount = selectResolvedItemsCount(resolved);
const unresolvedItemsCount = selectUnresolvedItemsCount(resolved);

const hasUnresolvedItems = unresolvedItemsCount > 0;
const hasResolvedItems = resolvedItemsCount > 0;

const nothingToInsert =
(!hasUnresolvedItems && !hasResolvedItems) ||
(!hasResolvedItems && !includeUnresolved);

return (
<Modal
onClose={onClose}
Expand All @@ -83,37 +102,51 @@ const UploadFilterListModal: FC<PropsT> = ({
{t("uploadConceptListModal.error")}
</p>
)}
{resolved && (
<Section>
{hasResolvedItems && (
<Msg>
<SuccessIcon icon={faCheckCircle} />
{t("uploadConceptListModal.resolvedCodes", {
count: resolvedItemsCount,
})}
</Msg>
)}
{hasUnresolvedItems && (
<>
<Msg>
<ErrorIcon icon={faExclamationCircle} />
<span
dangerouslySetInnerHTML={{
__html: t("uploadConceptListModal.unknownCodes", {
count: unresolvedItemsCount,
}),
}}
/>
</Msg>
<ScrollableList
maxVisibleItems={3}
fullWidth
items={resolved.unknownCodes || []}
/>
</>
)}
</Section>
{hasUnresolvedItems && (
<Col>
<Msg>
<ErrorIcon icon={faExclamationCircle} />
<span
dangerouslySetInnerHTML={{
__html: t("uploadConceptListModal.unknownCodes", {
count: unresolvedItemsCount,
}),
}}
/>
</Msg>
<ScrollableList
maxVisibleItems={3}
fullWidth
items={resolved.unknownCodes || []}
/>
</Col>
)}
<Col>
{hasResolvedItems && (
<Msg>
<SuccessIcon icon={faCheckCircle} />
{t("uploadConceptListModal.resolvedCodes", {
count: resolvedItemsCount,
})}
</Msg>
)}
{(resolved.unknownCodes?.length || 0) > 0 && (
<InputCheckbox
value={includeUnresolved}
onChange={setIncludeUnresolved}
label={t("uploadConceptListModal.includeUnresolved")}
/>
)}
</Col>
<PrimaryButton
disabled={loading || nothingToInsert}
onClick={() => {
onSubmit(resolved, { includeUnresolved });
onClose();
}}
>
{t("uploadConceptListModal.insertNode")}
</PrimaryButton>
</Root>
</Modal>
);
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/js/ui-components/ImportModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ export const ImportModal = ({
) => {
e.stopPropagation();

const lines = textInput.split("\n").map((line) => line.trim());
const lines = textInput
.split("\n")
.map((line) => line.trim())
.filter((line) => line.length > 0);

onSubmit(lines, droppedFilename);
onClose();
Expand Down
39 changes: 23 additions & 16 deletions frontend/src/js/ui-components/InputCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { exists } from "../common/helpers/exists";
import InfoTooltip from "../tooltip/InfoTooltip";
import WithTooltip from "../tooltip/WithTooltip";

const Row = styled("div")`
const Row = styled("div")<{ $disabled?: boolean }>`
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
cursor: ${({ $disabled }) => ($disabled ? "not-allowed" : "pointer")};
`;

const Label = styled("span")`
Expand All @@ -17,7 +17,7 @@ const Label = styled("span")`
line-height: 1;
`;

const Container = styled("div")`
const Container = styled("div")<{ $disabled?: boolean }>`
flex-shrink: 0;
position: relative;
font-size: 22px;
Expand All @@ -26,6 +26,7 @@ const Container = styled("div")`
border: 2px solid ${({ theme }) => theme.col.blueGrayDark};
border-radius: ${({ theme }) => theme.borderRadius};
box-sizing: content-box;
opacity: ${({ $disabled }) => ($disabled ? 0.5 : 1)};
`;

const Checkmark = styled("div")`
Expand All @@ -49,16 +50,6 @@ const Checkmark = styled("div")`
}
`;

interface PropsType {
label: string;
className?: string;
tooltip?: string;
tooltipLazy?: boolean;
infoTooltip?: string;
value?: boolean;
onChange: (checked: boolean) => void;
}

const InputCheckbox = ({
label,
className,
Expand All @@ -67,10 +58,26 @@ const InputCheckbox = ({
infoTooltip,
value,
onChange,
}: PropsType) => (
<Row className={className} onClick={() => onChange(!value)}>
disabled,
}: {
label: string;
className?: string;
tooltip?: string;
tooltipLazy?: boolean;
infoTooltip?: string;
value?: boolean;
onChange: (checked: boolean) => void;
disabled?: boolean;
}) => (
<Row
className={className}
onClick={() => {
if (!disabled) onChange(!value);
}}
$disabled={disabled}
>
<WithTooltip text={tooltip} lazy={tooltipLazy}>
<Container>{!!value && <Checkmark />}</Container>
<Container $disabled={disabled}>{!!value && <Checkmark />}</Container>
</WithTooltip>
<Label>{label}</Label>
{exists(infoTooltip) && <InfoTooltip text={infoTooltip} />}
Expand Down
Loading

0 comments on commit 53b2d3c

Please sign in to comment.