diff --git a/CHANGELOG.md b/CHANGELOG.md index be1d2819d..bca837e01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ You can also check the [release page](https://github.com/visualize-admin/visuali ## Unreleased -Nothing yet. +- Metadata is now shown in a dedicated panel that can be reached both from editor & published mode ## [3.15.0] - 2022-11-29 diff --git a/app/charts/area/areas-state.tsx b/app/charts/area/areas-state.tsx index 12cb40d9b..8e18dfcff 100644 --- a/app/charts/area/areas-state.tsx +++ b/app/charts/area/areas-state.tsx @@ -47,6 +47,7 @@ import { formatNumberWithUnit, useTimeFormatUnit, } from "@/formatters"; +import { DimensionMetadataFragment } from "@/graphql/query-hooks"; import { getPalette } from "@/palettes"; import { sortByIndex } from "@/utils/array"; import { estimateTextWidth } from "@/utils/estimate-text-width"; @@ -70,7 +71,7 @@ export interface AreasState extends CommonChartState { segments: string[]; colors: ScaleOrdinal; yAxisLabel: string; - yAxisDescription: string | undefined; + yAxisDimension: DimensionMetadataFragment; chartWideData: ArrayLike; allDataWide: ArrayLike; series: $FixMe[]; @@ -202,7 +203,6 @@ const useAreasState = ( } const yAxisLabel = getLabelWithUnit(yMeasure); - const yAxisDescription = yMeasure.description || undefined; /** Ordered segments */ const segmentSorting = fields.segment?.sorting; @@ -404,7 +404,7 @@ const useAreasState = ( yScale, getSegment, yAxisLabel, - yAxisDescription, + yAxisDimension: yMeasure, segments, colors, chartWideData, diff --git a/app/charts/column/columns-grouped-state.tsx b/app/charts/column/columns-grouped-state.tsx index 1c64a1670..aa03c395c 100644 --- a/app/charts/column/columns-grouped-state.tsx +++ b/app/charts/column/columns-grouped-state.tsx @@ -51,6 +51,7 @@ import { } from "@/configurator/components/ui-helpers"; import { isTemporalDimension, Observation } from "@/domain/data"; import { useFormatNumber, formatNumberWithUnit } from "@/formatters"; +import { DimensionMetadataFragment } from "@/graphql/query-hooks"; import { getPalette } from "@/palettes"; import { sortByIndex } from "@/utils/array"; import { @@ -77,7 +78,7 @@ export interface GroupedColumnsState extends CommonChartState { segments: string[]; colors: ScaleOrdinal; yAxisLabel: string; - yAxisDescription: string | undefined; + yAxisDimension: DimensionMetadataFragment; grouped: [string, Observation[]][]; getAnnotationInfo: (d: Observation) => TooltipInfo; showStandardError: boolean; @@ -312,7 +313,6 @@ const useGroupedColumnsState = ( } const yAxisLabel = getLabelWithUnit(yMeasure); - const yAxisDescription = yMeasure.description || undefined; // Group const grouped = useMemo(() => { @@ -452,7 +452,7 @@ const useGroupedColumnsState = ( getSegment, getSegmentLabel, yAxisLabel, - yAxisDescription, + yAxisDimension: yMeasure, segments, colors, grouped, diff --git a/app/charts/column/columns-stacked-state.tsx b/app/charts/column/columns-stacked-state.tsx index 0a986f8b2..10a521f84 100644 --- a/app/charts/column/columns-stacked-state.tsx +++ b/app/charts/column/columns-stacked-state.tsx @@ -51,6 +51,7 @@ import { Observer, useWidth } from "@/charts/shared/use-width"; import { ColumnFields, SortingOrder, SortingType } from "@/configurator"; import { isTemporalDimension, Observation } from "@/domain/data"; import { formatNumberWithUnit, useFormatNumber } from "@/formatters"; +import { DimensionMetadataFragment } from "@/graphql/query-hooks"; import { getPalette } from "@/palettes"; import { sortByIndex } from "@/utils/array"; import { @@ -75,7 +76,7 @@ export interface StackedColumnsState extends CommonChartState { segments: string[]; colors: ScaleOrdinal; yAxisLabel: string; - yAxisDescription: string | undefined; + yAxisDimension: DimensionMetadataFragment; chartWideData: ArrayLike; allDataWide: ArrayLike; grouped: [string, Observation[]][]; @@ -325,7 +326,6 @@ const useColumnsStackedState = ( } const yAxisLabel = getLabelWithUnit(yMeasure); - const yAxisDescription = yMeasure.description || undefined; const yScale = scaleLinear().domain(yStackDomain).nice(); @@ -507,7 +507,7 @@ const useColumnsStackedState = ( getSegment, getSegmentLabel, yAxisLabel, - yAxisDescription, + yAxisDimension: yMeasure, segments, colors, chartWideData, diff --git a/app/charts/column/columns-state.tsx b/app/charts/column/columns-state.tsx index 6992c4f26..8d9ab0b66 100644 --- a/app/charts/column/columns-state.tsx +++ b/app/charts/column/columns-state.tsx @@ -53,7 +53,11 @@ import { formatNumberWithUnit, useTimeFormatUnit, } from "@/formatters"; -import { TemporalDimension, TimeUnit } from "@/graphql/query-hooks"; +import { + DimensionMetadataFragment, + TemporalDimension, + TimeUnit, +} from "@/graphql/query-hooks"; import { getPalette } from "@/palettes"; import { getSortingOrders, @@ -79,7 +83,7 @@ export interface ColumnsState extends CommonChartState { segments: string[]; colors: ScaleOrdinal; yAxisLabel: string; - yAxisDescription: string | undefined; + yAxisDimension: DimensionMetadataFragment; getAnnotationInfo: (d: Observation) => TooltipInfo; showStandardError: boolean; } @@ -229,7 +233,6 @@ const useColumnsState = ( } const yAxisLabel = getLabelWithUnit(yMeasure); - const yAxisDescription = yMeasure.description || undefined; const { left, bottom } = useChartPadding( yScale, @@ -358,7 +361,7 @@ const useColumnsState = ( getSegment, getSegmentLabel, yAxisLabel, - yAxisDescription, + yAxisDimension: yMeasure, segments, colors, getAnnotationInfo, diff --git a/app/charts/line/lines-state.tsx b/app/charts/line/lines-state.tsx index 819a13f67..17da947e1 100644 --- a/app/charts/line/lines-state.tsx +++ b/app/charts/line/lines-state.tsx @@ -40,6 +40,7 @@ import { formatNumberWithUnit, useTimeFormatUnit, } from "@/formatters"; +import { DimensionMetadataFragment } from "@/graphql/query-hooks"; import { getPalette } from "@/palettes"; import { sortByIndex } from "@/utils/array"; import { estimateTextWidth } from "@/utils/estimate-text-width"; @@ -62,7 +63,7 @@ export interface LinesState extends CommonChartState { colors: ScaleOrdinal; xAxisLabel: string; yAxisLabel: string; - yAxisDescription: string | undefined; + yAxisDimension: DimensionMetadataFragment; grouped: Map; chartWideData: ArrayLike; allDataWide: ArrayLike; @@ -184,7 +185,6 @@ const useLinesState = ( } const yAxisLabel = getLabelWithUnit(yMeasure); - const yAxisDescription = yMeasure.description || undefined; const segmentDimension = useMemo(() => { return ( @@ -345,7 +345,7 @@ const useLinesState = ( getSegmentLabel, xAxisLabel, yAxisLabel, - yAxisDescription, + yAxisDimension: yMeasure, segments, colors, grouped: preparedDataGroupedBySegment, diff --git a/app/charts/scatterplot/scatterplot-state.tsx b/app/charts/scatterplot/scatterplot-state.tsx index 4b574778f..ec2baf0ed 100644 --- a/app/charts/scatterplot/scatterplot-state.tsx +++ b/app/charts/scatterplot/scatterplot-state.tsx @@ -28,6 +28,7 @@ import { ScatterPlotFields } from "@/configurator"; import { mkNumber } from "@/configurator/components/ui-helpers"; import { DimensionValue, Observation } from "@/domain/data"; import { useFormatNumber } from "@/formatters"; +import { DimensionMetadataFragment } from "@/graphql/query-hooks"; import { getPalette } from "@/palettes"; import { estimateTextWidth } from "@/utils/estimate-text-width"; @@ -43,9 +44,9 @@ export interface ScatterplotState extends CommonChartState { getSegment: (d: Observation) => string; colors: ScaleOrdinal; xAxisLabel: string; - xAxisDescription: string | undefined; + xAxisDimension: DimensionMetadataFragment; yAxisLabel: string; - yAxisDescription: string | undefined; + yAxisDimension: DimensionMetadataFragment; getSegmentLabel: (s: string) => string; getAnnotationInfo: (d: Observation, values: Observation[]) => TooltipInfo; } @@ -93,7 +94,6 @@ const useScatterplotState = ({ } const xAxisLabel = getLabelWithUnit(xMeasure); - const xAxisDescription = xMeasure.description || undefined; const xMinValue = Math.min(mkNumber(min(preparedData, (d) => getX(d))), 0); const xMaxValue = max(preparedData, (d) => getX(d)) as number; @@ -107,7 +107,6 @@ const useScatterplotState = ({ } const yAxisLabel = getLabelWithUnit(yMeasure); - const yAxisDescription = yMeasure.description || undefined; const yMinValue = Math.min(mkNumber(min(preparedData, (d) => getY(d))), 0); const yMaxValue = max(preparedData, getY) as number; @@ -243,9 +242,9 @@ const useScatterplotState = ({ getSegment, colors, xAxisLabel, - xAxisDescription, + xAxisDimension: xMeasure, yAxisLabel, - yAxisDescription, + yAxisDimension: yMeasure, getAnnotationInfo, getSegmentLabel, }; diff --git a/app/charts/shared/axis-height-linear.tsx b/app/charts/shared/axis-height-linear.tsx index 381fb5756..d504a5077 100644 --- a/app/charts/shared/axis-height-linear.tsx +++ b/app/charts/shared/axis-height-linear.tsx @@ -10,8 +10,8 @@ import { LinesState } from "@/charts/line/lines-state"; import { ScatterplotState } from "@/charts/scatterplot/scatterplot-state"; import { useChartState } from "@/charts/shared/use-chart-state"; import { useChartTheme } from "@/charts/shared/use-chart-theme"; +import { OpenMetadataPanelWrapper } from "@/components/metadata-panel"; import { useFormatNumber } from "@/formatters"; -import { MaybeTooltip } from "@/utils/maybe-tooltip"; export const TICK_MIN_HEIGHT = 50; @@ -23,7 +23,7 @@ export const AxisHeightLinear = () => { const ref = useRef(null); const formatNumber = useFormatNumber({ decimals: "auto" }); - const { yScale, yAxisLabel, yAxisDescription, bounds } = useChartState() as + const { yScale, yAxisLabel, yAxisDimension, bounds } = useChartState() as | AreasState | ColumnsState | GroupedColumnsState @@ -61,19 +61,11 @@ export const AxisHeightLinear = () => { return ( <> - - - - {yAxisLabel} - - - + + + {yAxisLabel} + + { const formatNumber = useFormatNumber(); - const { xScale, bounds, xAxisLabel, xAxisDescription } = + const { xScale, bounds, xAxisLabel, xAxisDimension } = useChartState() as ScatterplotState; const { chartWidth, chartHeight, margins } = bounds; const { labelColor, labelFontSize, gridColor, fontFamily } = useChartTheme(); @@ -51,18 +51,17 @@ export const AxisWidthLinear = () => { return ( <> - + {xAxisLabel} - + { @@ -268,10 +270,13 @@ const DataFilterGenericDimension = ({ return ( setSearchInput(e.target.value.toLowerCase())} - placeholder={t({ - id: "select.controls.metadata.search", - message: "Jump to...", - })} - startAdornment={ - - - - } - sx={{ typography: "body2" }} - /> - {filteredDimensions.map((d) => ( - - - + {selectedDimension ? ( + + clearSelectedDimension()}> + Back + + + + + + ) : ( + + v && setSelectedDimension(v.value)} + inputValue={inputValue} + onInputChange={(_, v) => setInputValue(v.toLowerCase())} + options={options} + ListboxProps={{ className: classes.searchInputResultList }} + renderInput={(params) => ( + + + + ), + sx: { typography: "body2" }, + }} + /> + )} + renderOption={(props, option, { inputValue }) => { + const matches = match(option.label, inputValue, { + insideWords: true, + }); + const parts = parse(option.label, matches); + + return ( +
  • +
    + {parts.map(({ text, highlight }, i) => ( + + {text} + + ))} +
    +
  • + ); + }} + clearIcon={null} /> - - {d.label} - -
    - {d.description} -
    - ))} + {dimensions.map((d) => ( + + ))} + + )} + ); }; + +const TabPanelDataDimension = ({ + dim, + expandable, +}: { + dim: DimensionMetadataFragment; + expandable: boolean; +}) => { + const classes = useOtherStyles(); + const { setSelectedDimension } = useMetadataPanelStoreActions(); + const { description, showExpandButton } = React.useMemo(() => { + if (expandable && dim.description && dim.description.length > 180) { + return { + description: dim.description.slice(0, 180) + "…", + showExpandButton: true, + }; + } + + return { + description: dim.description, + showExpandButton: false, + }; + }, [dim.description, expandable]); + const iconName = React.useMemo(() => { + return getDimensionIconName(dim.__typename); + }, [dim.__typename]); + + return ( +
    + + + + {dim.label} + + + {description && {description}} + {showExpandButton && ( + + )} +
    + ); +}; diff --git a/app/components/select-tree.tsx b/app/components/select-tree.tsx index a984293b9..627e94f12 100644 --- a/app/components/select-tree.tsx +++ b/app/components/select-tree.tsx @@ -265,8 +265,7 @@ export type SelectTreeProps = { controls?: React.ReactNode; onChange: (ev: { target: { value: NodeId } }) => void; disabled?: boolean; - tooltipText?: string; - label?: string; + label?: React.ReactNode; onOpen?: () => void; onClose?: () => void; open?: boolean; @@ -287,7 +286,6 @@ function SelectTree({ options, value, onChange, - tooltipText, disabled, controls, onOpen, @@ -478,7 +476,7 @@ function SelectTree({ return (
    {label && ( -