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

feat: Improve search options for add dataset dialog #1917

Merged
merged 10 commits into from
Nov 26, 2024
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ You can also check the

# Unreleased

Nothing yet.
- Features
- Made it possible to sort the cube search results and filter by draft
datasets when looking for a cube to merge

# [5.0.1] - 2024-11-26

Expand Down
171 changes: 111 additions & 60 deletions app/browser/dataset-browse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,22 +199,7 @@ export const SearchDatasetControls = ({
onSetOrder,
} = browseState;

const order = stateOrder || SearchCubeResultOrder.CreatedDesc;
const options = [
{
value: SearchCubeResultOrder.Score,
label: t({ id: "dataset.order.relevance", message: `Relevance` }),
},
{
value: SearchCubeResultOrder.TitleAsc,
label: t({ id: "dataset.order.title", message: `Title` }),
},
{
value: SearchCubeResultOrder.CreatedDesc,
label: t({ id: "dataset.order.newest", message: `Newest` }),
},
];

const order = stateOrder ?? SearchCubeResultOrder.CreatedDesc;
const isSearching = search !== "" && search !== undefined;

const onToggleIncludeDrafts = useEvent(async () => {
Expand All @@ -228,56 +213,121 @@ export const SearchDatasetControls = ({

return (
<Flex sx={{ justifyContent: "space-between", alignItems: "center", mb: 2 }}>
<Typography
variant="body2"
fontWeight={700}
aria-live="polite"
data-testid="search-results-count"
>
{cubes.length > 0 && (
<Plural
id="dataset.results"
value={cubes.length}
zero="No datasets"
one="# dataset"
other="# datasets"
/>
)}
</Typography>

<SearchDatasetResultsCount cubes={cubes} />
<Flex sx={{ alignItems: "center" }}>
<Checkbox
label={t({
id: "dataset.includeDrafts",
message: "Include draft datasets",
})}
name="dataset-include-drafts"
value="dataset-include-drafts"
<SearchDatasetDraftsControl
checked={includeDrafts}
onChange={onToggleIncludeDrafts}
/>
<label htmlFor="datasetSort">
<Typography variant="body2" fontWeight={700}>
<Trans id="dataset.sortby">Sort by</Trans>
</Typography>
</label>

<MinimalisticSelect
id="datasetSort"
smaller
autoWidth
<SearchDatasetSortControl
value={order}
data-testid="datasetSort"
options={isSearching ? options : options.slice(1)}
onChange={(e) => {
onSetOrder(e.target.value as SearchCubeResultOrder);
}}
onChange={onSetOrder}
disableScore={isSearching}
/>
</Flex>
</Flex>
);
};

export const SearchDatasetResultsCount = ({
cubes,
}: {
cubes: SearchCubeResult[];
}) => {
return (
<Typography
variant="body2"
fontWeight={700}
aria-live="polite"
data-testid="search-results-count"
color="secondary.main"
>
{cubes.length > 0 && (
<Plural
id="dataset.results"
value={cubes.length}
zero="No datasets"
one="# dataset"
other="# datasets"
/>
)}
</Typography>
);
};

export const SearchDatasetDraftsControl = ({
checked,
onChange,
}: {
checked: boolean;
onChange: (value: boolean) => void;
}) => {
return (
<Checkbox
label={t({
id: "dataset.includeDrafts",
message: "Include draft datasets",
})}
name="dataset-include-drafts"
value="dataset-include-drafts"
checked={checked}
onChange={() => onChange(!checked)}
/>
);
};

export const SearchDatasetSortControl = ({
value,
onChange,
disableScore,
}: {
value: SearchCubeResultOrder;
onChange: (order: SearchCubeResultOrder) => void;
disableScore?: boolean;
}) => {
const options = useMemo(() => {
const options = [
{
value: SearchCubeResultOrder.Score,
label: t({ id: "dataset.order.relevance", message: "Relevance" }),
},
{
value: SearchCubeResultOrder.TitleAsc,
label: t({ id: "dataset.order.title", message: "Title" }),
},
{
value: SearchCubeResultOrder.CreatedDesc,
label: t({ id: "dataset.order.newest", message: "Newest" }),
},
];

return disableScore
? options.filter((o) => o.value !== SearchCubeResultOrder.Score)
: options;
}, [disableScore]);

return (
<Box style={{ display: "flex", alignItems: "center", gap: 1 }}>
<label htmlFor="datasetSort">
<Typography variant="body2" fontWeight={700}>
<Trans id="dataset.sortby">Sort by</Trans>
</Typography>
</label>
<MinimalisticSelect
id="datasetSort"
data-testid="datasetSort"
smaller
autoWidth
value={value}
options={options}
onChange={(e) => {
onChange(e.target.value as SearchCubeResultOrder);
}}
/>
</Box>
);
};

type NavItemTheme = {
activeBg: string;
activeTextColor: string;
Expand Down Expand Up @@ -980,7 +1030,7 @@ export const DatasetResults = ({
}

return (
<>
<div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must this be a div?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, otherwise &:not(:first-child) CSS selector can't target a proper element 🥹

{cubes.map(({ cube, highlightedTitle, highlightedDescription }) => (
<DatasetResult
key={cube.iri}
Expand All @@ -990,7 +1040,7 @@ export const DatasetResults = ({
{...datasetResultProps?.({ cube })}
/>
))}
</>
</div>
);
};

Expand All @@ -1002,10 +1052,11 @@ const useResultStyles = makeStyles((theme: Theme) => ({
color: theme.palette.grey[700],
textAlign: "left",
padding: `${theme.spacing(4)} 0`,
borderTopColor: theme.palette.grey[300],
borderTopStyle: "solid",
borderTopWidth: 1,
boxShadow: "none",

"&:not(:first-child)": {
borderTop: `1px solid ${theme.palette.grey[300]}`,
},
},

titleClickable: {
Expand Down
33 changes: 17 additions & 16 deletions app/components/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ export const MinimalisticSelect = (props: MinimalisticSelectProps) => {
onChange,
smaller = false,
disabled,
sx,
...rest
} = props;

Expand All @@ -559,21 +560,6 @@ export const MinimalisticSelect = (props: MinimalisticSelectProps) => {
</Label>
)}
<MUISelect
sx={{
borderColor: "transparent",
fontSize: smaller ? ["0.625rem", "0.75rem", "0.75rem"] : "inherit",
lineHeight: "normal !important",

backgroundColor: "transparent",
p: 0,
pr: 2,
pl: 1,
mr: 1, // Fix for Chrome which cuts of the label otherwise
":focus": {
outline: "none",
borderColor: "primary.main",
},
}}
size={smaller ? "small" : "medium"}
variant="standard"
id={id}
Expand All @@ -586,13 +572,28 @@ export const MinimalisticSelect = (props: MinimalisticSelectProps) => {
{...props}
style={{
...props.style,
right: 12,
transition: "transform 0.1s",
}}
>
<Icon name="chevronDown" size={16} />
</span>
)}
sx={{
borderColor: "transparent",
fontSize: smaller ? ["0.625rem", "0.75rem", "0.75rem"] : "inherit",
lineHeight: "normal !important",
backgroundColor: "transparent",
p: 0,
pl: 1,
":focus": {
outline: "none",
borderColor: "primary.main",
},
"& .MuiInput-input": {
paddingRight: "1.25rem !important",
},
...sx,
}}
{...rest}
>
{options.map((opt) => (
Expand Down
Loading
Loading