Skip to content

Commit

Permalink
Merge pull request #837 from visualize-admin/feat/hierarchy-published
Browse files Browse the repository at this point in the history
  • Loading branch information
ptbrowne authored Nov 11, 2022
2 parents 8c784ab + 013816d commit 09bc13c
Show file tree
Hide file tree
Showing 12 changed files with 349 additions and 136 deletions.
4 changes: 0 additions & 4 deletions app/charts/pie/pie-state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@ const usePieState = (
const getY = useOptionalNumericVariable(fields.y.componentIri);
const getX = useSegment(fields.segment.componentIri);

// Sort data
const sortingOrder = fields.segment.sorting?.sortingOrder;

// Data actually sorted in pie(),
const plottableData = usePlottableData({
data: data,
Expand Down Expand Up @@ -155,7 +152,6 @@ const usePieState = (
plottableData,
segmentDimension,
segmentValuesByLabel,
sortingOrder,
]);

const getSegmentLabel = useCallback(
Expand Down
83 changes: 50 additions & 33 deletions app/charts/shared/chart-data-filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,27 @@ import {
ChartConfig,
DataSource,
InteractiveFiltersDataConfig,
OptionGroup,
Option,
} from "@/configurator";
import { TimeInput } from "@/configurator/components/field";
import {
getTimeIntervalFormattedSelectOptions,
getTimeIntervalWithProps,
} from "@/configurator/components/ui-helpers";
import useHierarchyParents from "@/configurator/components/use-hierarchy-parents";
import { FIELD_VALUE_NONE } from "@/configurator/constants";
import { isTemporalDimension } from "@/domain/data";
import { useTimeFormatLocale } from "@/formatters";
import { TimeUnit, useDimensionValuesQuery } from "@/graphql/query-hooks";
import {
Dimension,
TemporalDimension,
TimeUnit,
useDimensionValuesQuery,
} from "@/graphql/query-hooks";
import { Icon } from "@/icons";
import { useLocale } from "@/locales/use-locale";
import { makeOptionGroups } from "@/utils/hierarchy";

export const ChartDataFilters = ({
dataSet,
Expand Down Expand Up @@ -90,6 +99,7 @@ export const ChartDataFilters = ({

{componentIris.length > 0 && (
<Box
data-testid="published-chart-interactive-filters"
sx={{
display: filtersVisible ? "grid" : "none",
columnGap: 3,
Expand Down Expand Up @@ -140,6 +150,18 @@ const DataFilter = ({
},
});

const { data: hierarchyParents } = useHierarchyParents({
datasetIri: dataSetIri,
dataSource,
dimension: data?.dataCubeByIri?.dimensionByIri!,
locale,
pause: !data?.dataCubeByIri?.dimensionByIri,
});

const optionGroups = React.useMemo(() => {
return makeOptionGroups(hierarchyParents);
}, [hierarchyParents]);

const setDataFilter = (e: SelectChangeEvent<unknown>) => {
dispatch({
type: "UPDATE_DATA_FILTER",
Expand Down Expand Up @@ -175,21 +197,15 @@ const DataFilter = ({
>
{!isTemporalDimension(dimension) ? (
<DataFilterBaseDimension
isKeyDimension={dimension.isKeyDimension}
label={dimension.label}
options={dimension.values}
value={value as string}
tooltipText={dimension.description || undefined}
dimension={dimension}
optionGroups={optionGroups}
onChange={setDataFilter}
value={value as string}
/>
) : dimension.timeUnit === TimeUnit.Year ? (
<DataFilterTemporalDimension
isKeyDimension={dimension.isKeyDimension}
label={dimension.label}
options={dimension.values}
value={value as string}
timeUnit={dimension.timeUnit}
timeFormat={dimension.timeFormat}
dimension={dimension}
onChange={setDataFilter}
/>
) : null}
Expand All @@ -201,24 +217,26 @@ const DataFilter = ({
};

const DataFilterBaseDimension = ({
isKeyDimension,
label,
options,
dimension,
value,
tooltipText,
onChange,
options: propOptions,
optionGroups,
}: {
isKeyDimension: boolean;
label: string;
options: Array<{ label: string; value: string }>;
dimension: Dimension;
value: string;
tooltipText?: string;
onChange: (e: SelectChangeEvent<unknown>) => void;
options?: Array<{ label: string; value: string }>;
optionGroups?: [OptionGroup, Option[]][];
}) => {
const noneLabel = t({
id: "controls.dimensionvalue.none",
message: `No Filter`,
});

const { label, isKeyDimension, description: tooltipText } = dimension;
const options = propOptions || dimension.values;

const allOptions = React.useMemo(() => {
return isKeyDimension
? options
Expand All @@ -237,32 +255,33 @@ const DataFilterBaseDimension = ({
id="dataFilterBaseDimension"
label={label}
options={allOptions}
optionGroups={optionGroups}
value={value}
tooltipText={tooltipText}
tooltipText={tooltipText || undefined}
onChange={onChange}
/>
);
};

const DataFilterTemporalDimension = ({
isKeyDimension,
label,
options,
timeUnit,
timeFormat,
dimension,
value,
tooltipText,
onChange,
}: {
isKeyDimension: boolean;
label: string;
options: Array<{ label: string; value: string }>;
timeUnit: TimeUnit;
timeFormat: string;
dimension: TemporalDimension;
value: string;
tooltipText?: string;
onChange: (e: SelectChangeEvent<unknown>) => void;
}) => {
const {
isKeyDimension,
label,
values: options,
timeUnit,
timeFormat,
} = dimension;

const formatLocale = useTimeFormatLocale();
const timeIntervalWithProps = React.useMemo(
() =>
Expand All @@ -282,11 +301,9 @@ const DataFilterTemporalDimension = ({
if (timeIntervalWithProps.range < 100) {
return (
<DataFilterBaseDimension
isKeyDimension={isKeyDimension}
label={label}
dimension={dimension}
options={timeIntervalOptions}
value={value}
tooltipText={tooltipText}
onChange={onChange}
/>
);
Expand Down
136 changes: 100 additions & 36 deletions app/components/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Box,
BoxProps,
ButtonBase,
Paper,
Checkbox as MUICheckbox,
InputProps,
FormControlLabel,
Expand All @@ -19,11 +20,16 @@ import {
MenuItem,
TypographyProps,
Stack,
CircularProgress,
styled,
PaperProps,
} from "@mui/material";
import { useId } from "@reach/auto-id";
import { timeFormat } from "d3-time-format";
import flatten from "lodash/flatten";
import React, { useContext } from "react";
import { ChangeEvent, ReactNode, useCallback, useMemo } from "react";
import { forwardRef } from "react";

import VisuallyHidden from "@/components/visually-hidden";
import {
Expand Down Expand Up @@ -253,6 +259,54 @@ export type Group = {
value: string;
};

// Copied over from https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Menu/Menu.js
const MenuPaper = styled(Paper, {
name: "MuiMenu",
slot: "Paper",
overridesResolver: (_props: PaperProps, styles) => styles.paper,
})({
// specZ: The maximum height of a simple menu should be one or more rows less than the view
// height. This ensures a tapable area outside of the simple menu with which to dismiss
// the menu.
maxHeight: "calc(100% - 96px)",
// Add iOS momentum scrolling for iOS < 13.0
WebkitOverflowScrolling: "touch",
});

const LoadingMenuPaperContext = React.createContext(
false as boolean | undefined
);

/**
* Shows a loading indicator when hierarchy is loading
*/
const LoadingMenuPaper = forwardRef<HTMLDivElement>(
(props: PaperProps, ref) => {
const loading = useContext(LoadingMenuPaperContext);
return (
<MenuPaper {...props} ref={ref}>
{props.children}
{loading ? (
<Box
px={4}
py={2}
sx={{
position: "sticky",
bottom: 0,
backgroundColor: "warning.light",
}}
>
<Typography variant="body2">
<Trans id="hint.loading.data" />
<CircularProgress size={12} color="inherit" />
</Typography>
</Box>
) : null}
</MenuPaper>
);
}
);

export const Select = ({
label,
id,
Expand All @@ -265,6 +319,7 @@ export const Select = ({
optionGroups,
tooltipText,
onOpen,
loading,
}: {
id: string;
options: Option[];
Expand All @@ -274,6 +329,7 @@ export const Select = ({
controls?: React.ReactNode;
optionGroups?: [OptionGroup, Option[]][];
tooltipText?: string;
loading?: boolean;
} & SelectProps) => {
const locale = useLocale();

Expand All @@ -294,42 +350,50 @@ export const Select = ({
}, [optionGroups, sortOptions, locale, options]);

return (
<Box>
{label && (
<Label htmlFor={id} smaller tooltipText={tooltipText} sx={{ mb: 1 }}>
{label}
{controls}
</Label>
)}
<MUISelect
sx={{
width: "100%",
}}
id={id}
name={id}
onChange={onChange}
value={value}
disabled={disabled}
onOpen={onOpen}
>
{sortedOptions.map((opt) => {
if (!opt.value) {
return null;
}
return opt.type === "group" ? (
<ListSubheader key={opt.label}>{opt.label}</ListSubheader>
) : (
<MenuItem
key={opt.value}
disabled={opt.disabled}
value={opt.value ?? undefined}
>
{opt.label}
</MenuItem>
);
})}
</MUISelect>
</Box>
<LoadingMenuPaperContext.Provider value={loading}>
<Box>
{label && (
<Label htmlFor={id} smaller tooltipText={tooltipText} sx={{ mb: 1 }}>
{label}
{controls}
</Label>
)}
<MUISelect
sx={{
width: "100%",
}}
id={id}
name={id}
onChange={onChange}
value={value}
disabled={disabled}
onOpen={onOpen}
MenuProps={{
PaperProps: {
// @ts-ignore - It works
component: LoadingMenuPaper,
},
}}
>
{sortedOptions.map((opt) => {
if (!opt.value) {
return null;
}
return opt.type === "group" ? (
<ListSubheader key={opt.label}>{opt.label}</ListSubheader>
) : (
<MenuItem
key={opt.value}
disabled={opt.disabled}
value={opt.value ?? undefined}
>
{opt.label}
</MenuItem>
);
})}
</MUISelect>
</Box>
</LoadingMenuPaperContext.Provider>
);
};

Expand Down
Loading

1 comment on commit 09bc13c

@vercel
Copy link

@vercel vercel bot commented on 09bc13c Nov 11, 2022

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

visualization-tool – ./

visualization-tool-git-main-ixt1.vercel.app
visualization-tool-ixt1.vercel.app
visualization-tool-alpha.vercel.app

Please sign in to comment.