Skip to content

Commit

Permalink
Merge pull request #1512 from visualize-admin/feat/joined-dims-metadata
Browse files Browse the repository at this point in the history
Joined dimensions improvements
  • Loading branch information
ptbrowne authored May 8, 2024
2 parents dc1522c + c66d376 commit 12d66cf
Show file tree
Hide file tree
Showing 11 changed files with 295 additions and 82 deletions.
45 changes: 45 additions & 0 deletions app/components/info-icon-tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Theme, Tooltip, TooltipProps, Typography } from "@mui/material";
import { makeStyles } from "@mui/styles";
import React from "react";

import { Icon } from "@/icons";

type InfoIconTooltipProps = {
title: NonNullable<React.ReactNode>;
};

const useStyles = makeStyles((theme: Theme) => ({
tooltip: { width: 180, padding: theme.spacing(1, 2), lineHeight: "18px" },
icon: {
color: theme.palette.primary.main,
pointerEvents: "auto",
},
}));

export const InfoIconTooltip = (
props: InfoIconTooltipProps & Omit<TooltipProps, "children">
) => {
const classes = useStyles();
const { title, componentsProps, ...rest } = props;

return (
<Tooltip
arrow
placement="top"
title={
<Typography variant="caption" color="secondary">
{title}
</Typography>
}
componentsProps={{
...componentsProps,
tooltip: { className: classes.tooltip },
}}
{...rest}
>
<Typography>
<Icon name="infoOutline" size={16} className={classes.icon} />
</Typography>
</Tooltip>
);
};
50 changes: 48 additions & 2 deletions app/components/metadata-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ import orderBy from "lodash/orderBy";
import sortBy from "lodash/sortBy";
import uniqBy from "lodash/uniqBy";
import { useRouter } from "next/router";
import React, { useMemo, useState, useEffect, useCallback } from "react";
import React, { useCallback, useEffect, useMemo, useState } from "react";

import { DatasetMetadata } from "@/components/dataset-metadata";
import { Error, Loading } from "@/components/hint";
import { InfoIconTooltip } from "@/components/info-icon-tooltip";
import {
useMetadataPanelStore,
useMetadataPanelStoreActions,
Expand Down Expand Up @@ -638,6 +639,23 @@ const TabPanelDataDimension = ({
}, [cubeIri, dim, expanded]);

const locale = useLocale();
const cubesIri = useMemo(() => {
return isJoinByComponent(dim)
? dim.originalIris.map((x) => x.cubeIri)
: [dim.cubeIri];
}, [dim]);
const [cubesQuery] = useDataCubesMetadataQuery({
variables: {
locale,
sourceType: dataSource.type,
sourceUrl: dataSource.url,
cubeFilters: cubesIri.map((iri) => ({ iri })),
},
});
const cubesByIri = useMemo(
() => keyBy(cubesQuery.data?.dataCubesMetadata, (x) => x.iri),
[cubesQuery.data?.dataCubesMetadata]
);
const [componentsQuery] = useDataCubesComponentsQuery({
pause: !expanded,
variables: {
Expand Down Expand Up @@ -690,7 +708,19 @@ const TabPanelDataDimension = ({
{label}
</Button>
{isJoinByComponent(dim) ? (
<JoinByChip label={<Trans id="dimension.joined">Joined</Trans>} />
<>
<JoinByChip
label={<Trans id="dimension.joined">Joined</Trans>}
/>
<InfoIconTooltip
title={
<Trans id="dimension.joined-info-icon">
Joined dimensions integrate data from multiple datasets
</Trans>
}
placement="top-end"
/>
</>
) : null}
</Box>
{description && (
Expand All @@ -707,6 +737,22 @@ const TabPanelDataDimension = ({
component={Flex}
{...animationProps}
>
{isJoinByComponent(dim) ? (
<div>
<Typography variant="h5" gutterBottom>
Joined with
</Typography>
{dim.originalIris.map((x) =>
x.cubeIri === loadedDimension.cubeIri ? null : (
<div key={x.cubeIri}>
<Typography variant="body2">
{x.label} ({cubesByIri[x.cubeIri]?.title} )
</Typography>
</div>
)
)}
</div>
) : null}
<Typography
sx={{ mt: 2, color: "grey.800" }}
variant="body2"
Expand Down
123 changes: 107 additions & 16 deletions app/configurator/components/add-dataset-dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
import { Trans, t } from "@lingui/macro";
import { t, Trans } from "@lingui/macro";
import { LoadingButton } from "@mui/lab";
import {
Alert,
AlertProps,
Box,
Button,
Checkbox,
CircularProgress,
Collapse,
Dialog,
DialogActions,
dialogActionsClasses,
dialogClasses,
DialogContent,
dialogContentClasses,
DialogProps,
DialogTitle,
dialogTitleClasses,
Grow,
IconButton,
IconButtonProps,
InputAdornment,
Link,
ListItemText,
ListSubheader,
MenuItem,
Expand All @@ -29,10 +38,6 @@ import {
Tooltip,
Typography,
TypographyProps,
dialogActionsClasses,
dialogClasses,
dialogContentClasses,
dialogTitleClasses,
useEventCallback,
} from "@mui/material";
import { Theme } from "@mui/material/styles";
Expand All @@ -42,28 +47,28 @@ import groupBy from "lodash/groupBy";
import keyBy from "lodash/keyBy";
import uniq from "lodash/uniq";
import uniqBy from "lodash/uniqBy";
import { FormEvent, useEffect, useMemo, useState } from "react";
import { FormEvent, useCallback, useEffect, useMemo, useState } from "react";
import { useClient } from "urql";

import { DatasetResults, PartialSearchCube } from "@/browser/dataset-browse";
import { getPossibleChartTypes } from "@/charts";
import { Error as ErrorHint, Loading } from "@/components/hint";
import Tag from "@/components/tag";
import {
addDatasetInConfig,
ConfiguratorStateConfiguringChart,
DataSource,
addDatasetInConfig,
isConfiguring,
useConfiguratorState,
} from "@/configurator";
import { BetaTag } from "@/configurator/components/beta-tag";
import {
Dimension,
Measure,
Termset,
isJoinByComponent,
isStandardErrorDimension,
isTemporalDimensionWithTimeUnit,
Measure,
Termset,
} from "@/domain/data";
import { truthy } from "@/domain/types";
import {
Expand All @@ -78,15 +83,17 @@ import {
DataCubeComponentsQueryVariables,
SearchCubeFilterType,
SearchCubeResultOrder,
useDataCubeComponentTermsetsQuery,
useDataCubeComponentsQuery,
useDataCubeComponentTermsetsQuery,
useSearchCubesQuery,
} from "@/graphql/query-hooks";
import SvgIcFilter from "@/icons/components/IcFilter";
import SvgIcInfo from "@/icons/components/IcInfo";
import SvgIcRemove from "@/icons/components/IcRemove";
import SvgIcSearch from "@/icons/components/IcSearch";
import { useLocale } from "@/locales/use-locale";
import { exhaustiveCheck } from "@/utils/exhaustiveCheck";
import useLocalState from "@/utils/use-local-state";

const DialogCloseButton = (props: IconButtonProps) => {
return (
Expand Down Expand Up @@ -127,9 +134,27 @@ const useStyles = makeStyles((theme: Theme) => ({
minHeight: "calc(100vh - calc(30px * 2))",
},
},
dialogCloseArea: {
position: "absolute",
top: "1rem",
right: "1rem",
display: "flex",
gap: "0.5rem",
alignItems: "center",
},
newAnnotation: {
color: theme.palette.success.main,
},
listTag: {
whiteSpace: "break-spaces",
},
listItemSecondary: {
display: "flex",
flexWrap: "wrap",
alignItems: "center",
gap: 1,
paddingTop: theme.spacing(1),
},
}));

const NewAnnotation = (props: TypographyProps) => {
Expand All @@ -146,6 +171,51 @@ const NewAnnotation = (props: TypographyProps) => {
);
};

const useCautionAlert = () => {
const [isOpen, setIsOpen] = useLocalState("add-dataset-caution-alert", true);

return {
isOpen,
open: useCallback(() => setIsOpen(true), [setIsOpen]),
close: useCallback(() => setIsOpen(false), [setIsOpen]),
};
};

export const CautionAlert = ({
onConfirm,
...props
}: { onConfirm: () => void } & AlertProps) => {
return (
<Alert
{...props}
icon={<SvgIcInfo />}
severity="info"
sx={{ ...props.sx, typography: "body3", color: "text.primary" }}
>
<Trans id="dataset.search.caution.body">
The linking of different datasets carries risks such as data
inconsistencies, scalability issues, and unexpected correlations. Be
sure to use to merge datasets only when you are confident that data
should be merged together.
</Trans>
<Box sx={{ mt: 1 }}>
<Link
color="primary"
onClick={(ev) => {
ev.preventDefault();
onConfirm();
}}
href="#"
>
<Trans id="dataset.search.caution.acknowledge">
Understood, I&apos;ll proceed cautiously.
</Trans>
</Link>
</Box>
</Alert>
);
};

export type SearchOptions =
| {
type: "temporal";
Expand Down Expand Up @@ -827,6 +897,8 @@ export const DatasetDialog = ({
setOtherCube(otherCube);
};

const { isOpen, open, close } = useCautionAlert();

return (
<Dialog
{...props}
Expand All @@ -835,7 +907,17 @@ export const DatasetDialog = ({
fullWidth
className={clsx(classes.dialog, props.className)}
>
<DialogCloseButton onClick={(ev) => handleClose(ev, "escapeKeyDown")} />
<Box className={classes.dialogCloseArea}>
<Grow in={!isOpen}>
<IconButton color="primary" onClick={() => open()}>
<SvgIcInfo />
</IconButton>
</Grow>
<DialogCloseButton
onClick={(ev) => handleClose(ev, "escapeKeyDown")}
sx={{ position: "static" }}
/>
</Box>
{otherCube ? null : (
<>
<DialogTitle sx={{ typography: "h2" }}>
Expand All @@ -850,6 +932,10 @@ export const DatasetDialog = ({
/>
</DialogTitle>
<DialogContent>
<Collapse in={isOpen}>
<CautionAlert sx={{ mb: 4 }} onConfirm={() => close()} />
</Collapse>

<Typography variant="body1" mb="2rem">
<Trans id="chart.datasets.add-dataset-dialog.description">
You can only combine datasets that share dimensions with the
Expand Down Expand Up @@ -946,26 +1032,31 @@ export const DatasetDialog = ({
/>
<ListItemText
primary={<Tag type="dimension">{sd.label}</Tag>}
classes={{ secondary: classes.listItemSecondary }}
secondary={
sd.type === "temporal" ? (
<Tag type="termset">{sd.timeUnit}</Tag>
) : (
<Box
sx={{ display: "flex", flexWrap: "wrap", gap: 1 }}
>
<>
<Typography
variant="caption"
color="grey.600"
mr={2}
gutterBottom
component="div"
>
<Trans id="dataset-result.dimension-termset-contains" />
</Typography>
{sd.termsets.map((t) => (
<Tag key={t.iri} type="termset">
<Tag
key={t.iri}
type="termset"
className={classes.listTag}
>
{t.label}
</Tag>
))}
</Box>
</>
)
}
/>
Expand Down
Loading

0 comments on commit 12d66cf

Please sign in to comment.