Compare commits

...

9 Commits

Author SHA1 Message Date
Oisin Coveney
82f6a7ef4d Missed a spot 2025-02-27 13:26:23 -08:00
Oisin Coveney
b94f8a9ef9 Merge branch 'master' into add-widget-typing 2025-02-27 13:11:34 -08:00
Oisin Coveney
76fe1e881b Merge branch 'add-widget-typing' of https://github.com/metabase/metabase into add-widget-typing 2025-02-27 13:09:37 -08:00
Oisin Coveney
77ce2b034d Save progress 2025-01-09 11:00:30 -08:00
Oisin Coveney
feb355f7de Merge branch 'master' into add-widget-typing 2024-12-10 15:59:26 +02:00
Oisin Coveney
92d657ceab Merge branch 'master' into add-widget-typing 2024-12-09 16:07:35 +02:00
Oisin Coveney
0ec53b4150 Merge branch 'master' into add-widget-typing 2024-12-05 14:54:13 +02:00
Oisin Coveney
99c13a9a58 Try to change types without changing behavior 2024-12-03 15:40:32 +02:00
Oisin Coveney
8cd4f020ce Change initial types 2024-12-03 11:42:03 +02:00
22 changed files with 226 additions and 167 deletions

View File

@@ -1,5 +1,6 @@
import type { EmbeddingParameters } from "metabase/public/lib/types";
import type { PieRow } from "metabase/visualizations/echarts/pie/model/types";
import type { GraphMetricName } from "metabase/visualizations/types";
import type { Collection, CollectionId, LastEditInfo } from "./collection";
import type { DashCardId, Dashboard, DashboardId } from "./dashboard";
@@ -215,19 +216,21 @@ export interface ColumnSettings {
[key: string]: any;
}
export type OtherCategoryAggregationFn =
| "sum"
| "avg"
| "min"
| "max"
| "stddev"
| "median";
export type VisualizationSettings = {
"graph.show_values"?: boolean;
"stackable.stack_type"?: StackType;
"graph.show_stack_values"?: StackValuesDisplay;
"graph.max_categories_enabled"?: boolean;
"graph.max_categories"?: number;
"graph.other_category_aggregation_fn"?:
| "sum"
| "avg"
| "min"
| "max"
| "stddev"
| "median";
"graph.other_category_aggregation_fn"?: OtherCategoryAggregationFn;
// Table
"table.columns"?: TableColumnOrderSetting[];
@@ -263,7 +266,7 @@ export type VisualizationSettings = {
// Series
"graph.dimensions"?: string[];
"graph.metrics"?: string[];
"graph.metrics"?: GraphMetricName[];
// Series settings
series_settings?: Record<string, SeriesSettings>;
@@ -314,9 +317,8 @@ export type VisualizationSettings = {
"sankey.node_align"?: "left" | "right" | "justify";
"sankey.show_edge_labels"?: boolean;
"sankey.label_value_formatting"?: "auto" | "full" | "compact";
[key: string]: any;
} & EmbedVisualizationSettings;
} & EmbedVisualizationSettings &
Record<string, any>;
export type EmbedVisualizationSettings = {
iframe?: string;

View File

@@ -1,6 +1,6 @@
import type { CacheStrategy, LocalFieldReference } from "metabase-types/api";
import type { Card } from "./card";
import type { Card, OtherCategoryAggregationFn } from "./card";
import type { DatabaseId } from "./database";
import type { FieldFingerprint, FieldId, FieldVisibilityType } from "./field";
import type { Insight } from "./insight";
@@ -20,15 +20,10 @@ export type BinningMetadata = {
export type AggregationType =
| "count"
| "sum"
| "cum-sum"
| "cum-count"
| "distinct"
| "min"
| "max"
| "avg"
| "median"
| "stddev";
| OtherCategoryAggregationFn;
export interface DatasetColumn {
id?: FieldId;

View File

@@ -1,3 +1,4 @@
import type { GraphMetricName } from "metabase/visualizations/types";
import * as Lib from "metabase-lib";
import {
getColumnKey,
@@ -146,7 +147,7 @@ function syncColumns<T>({
}
type SyncColumnNamesOpts = {
settings: string[];
settings: (string | null)[];
newColumns: ColumnInfo[];
oldColumns: ColumnInfo[];
shouldCreateSetting?: (column: ColumnInfo) => boolean | undefined;
@@ -158,11 +159,11 @@ function syncColumnNames({
oldColumns,
shouldCreateSetting,
}: SyncColumnNamesOpts) {
return syncColumns({
return syncColumns<GraphMetricName>({
settings,
newColumns,
oldColumns,
getColumnName: setting => setting,
getColumnName: setting => setting ?? null,
setColumnName: (_, newName) => newName,
createSetting: column => column.name,
shouldCreateSetting,

View File

@@ -76,7 +76,7 @@ export const BaseChartSettings = ({
[chartSettings, series],
);
const styleWidget = useMemo(() => {
const styleWidget = useMemo((): Widget | null => {
const seriesSettingsWidget =
currentWidget && widgets.find(widget => widget.id === "series_settings");
@@ -133,7 +133,7 @@ export const BaseChartSettings = ({
return null;
}, [computedSettings, currentWidget, transformedSeries, widgets]);
const formattingWidget = useMemo(() => {
const formattingWidget = useMemo((): Widget | null => {
const widget =
currentWidget && widgets.find(widget => widget.id === currentWidget.id);

View File

@@ -28,7 +28,7 @@ function widget(widget: Partial<Widget> = {}): Widget {
section: "section-" + Math.random(),
props: {},
...widget,
};
} as Widget;
}
type SetupOpts = Partial<BaseChartSettingsProps>;

View File

@@ -1,15 +1,46 @@
import type { ComponentType } from "react";
import type {
VisualizationSettingDefinition,
WidgetComponentDef,
} from "metabase/visualizations/types";
import type Question from "metabase-lib/v1/Question";
import type { Series, VisualizationSettings } from "metabase-types/api";
// this type is not full, we need to extend it later
export type Widget = {
id: string;
export type Widget<
K extends keyof VisualizationSettings = keyof VisualizationSettings,
SettingsWidget extends ComponentType<any> = ComponentType<any>,
> = {
id: K;
value: VisualizationSettings[K];
section: string;
title: string;
hidden?: boolean;
props: Record<string, unknown>;
title?: string;
widget: (() => JSX.Element | null) | undefined;
};
marginBottom?: string;
disabled?: boolean;
set?: boolean;
onChange: (value: VisualizationSettings[K], question: Question) => void;
onChangeSettings: (
settings: VisualizationSettings,
question: Question,
) => void;
} & Omit<
VisualizationSettingDefinition<K>,
| "id"
| "value"
| "section"
| "title"
| "hidden"
| "marginBottom"
| "disabled"
| "props"
| "set"
| "widget"
> &
(SettingsWidget extends ComponentType<infer P>
? WidgetComponentDef<SettingsWidget, P, VisualizationSettings[K]>
: never);
export type CommonChartSettingsProps = {
series: Series;

View File

@@ -1,28 +1,30 @@
import cx from "classnames";
import type * as React from "react";
import PopoverS from "metabase/components/Popover/Popover.module.css";
import FormS from "metabase/css/components/form.module.css";
import { Box, Group, Icon, Text, Tooltip } from "metabase/ui";
import type { Widget } from "./ChartSettings";
import { Root } from "./ChartSettingsWidget.styled";
type Props = {
title?: string;
description?: string;
hint?: string;
hidden?: boolean;
disabled?: boolean;
widget?: React.ComponentType<{ id: string }>;
inline?: boolean;
marginBottom?: string;
props?: Record<string, unknown>;
noPadding?: boolean;
variant?: "default" | "form-field";
borderBottom?: boolean;
dataTestId?: string;
id: string;
};
} & Pick<
Widget,
| "id"
| "props"
| "widget"
| "disabled"
| "inline"
| "hidden"
| "title"
| "marginBottom"
>;
const ChartSettingsWidget = ({
title,

View File

@@ -1,5 +1,6 @@
import _ from "underscore";
import type { Widget } from "./ChartSettings";
import ChartSettingsWidget from "./ChartSettingsWidget";
import {
ChartSettingsWidgetListDivider,
@@ -7,7 +8,7 @@ import {
} from "./ChartSettingsWidgetList.styled";
interface ChartSettingsWidgetListProps {
widgets: { id: string; group?: string }[];
widgets: Widget[];
extraWidgetProps: Record<string, unknown>;
}

View File

@@ -5,14 +5,9 @@ import TippyPopover from "metabase/components/Popover/TippyPopover";
import CS from "metabase/css/core/index.css";
import { Box, Space, Tabs } from "metabase/ui";
import type { Widget } from "./ChartSettings";
import ChartSettingsWidget from "./ChartSettingsWidget";
interface Widget {
id: string;
section: string;
props: Record<string, unknown>;
}
interface ChartSettingsWidgetPopoverProps {
anchor: HTMLElement;
handleEndShowWidget: () => void;
@@ -28,7 +23,9 @@ export const ChartSettingsWidgetPopover = ({
const contentRef = useRef<HTMLDivElement>(null);
useEffect(() => {
sections.current = _.chain(widgets).pluck("section").unique().value();
sections.current = Array.from(
new Set(widgets.map(widget => widget.section)),
);
}, [widgets]);
const [currentSection, setCurrentSection] = useState("");

View File

@@ -2,20 +2,15 @@ import { useCallback } from "react";
import { t } from "ttag";
import { Checkbox, Select, Stack, Text } from "metabase/ui";
import type { VisualizationSettings } from "metabase-types/api";
import type { OtherCategoryAggregationFn } from "metabase-types/api";
import { ChartSettingInputNumeric } from "./ChartSettingInputNumeric";
import type { ChartSettingWidgetProps } from "./types";
type AggregationFunction = Exclude<
VisualizationSettings["graph.other_category_aggregation_fn"],
undefined
>;
export interface ChartSettingMaxCategoriesProps
extends ChartSettingWidgetProps<number> {
isEnabled?: boolean;
aggregationFunction: AggregationFunction;
aggregationFunction: NonNullable<OtherCategoryAggregationFn>;
}
export const ChartSettingMaxCategories = ({
@@ -33,10 +28,10 @@ export const ChartSettingMaxCategories = ({
);
const handleAggregationFunctionChange = useCallback(
(value: string | null) => {
(value: NonNullable<OtherCategoryAggregationFn>) => {
if (value) {
onChangeSettings({
"graph.other_category_aggregation_fn": value as AggregationFunction,
"graph.other_category_aggregation_fn": value,
});
}
},
@@ -76,7 +71,10 @@ export const ChartSettingMaxCategories = ({
);
};
const AGGREGATION_FN_OPTIONS = [
const AGGREGATION_FN_OPTIONS: {
label: string;
value: NonNullable<OtherCategoryAggregationFn>;
}[] = [
{ label: t`Sum`, value: "sum" },
{ label: t`Average`, value: "avg" },
{ label: t`Median`, value: "median" },

View File

@@ -48,25 +48,30 @@ import {
isXAxisScaleValid,
isYAxisUnpinFromZeroValid,
} from "metabase/visualizations/shared/settings/cartesian-chart";
import type { VisualizationSettingsDefinitions } from "metabase/visualizations/types";
import { getColumnKey } from "metabase-lib/v1/queries/utils/column-key";
import { isNumeric } from "metabase-lib/v1/types/utils/isa";
import type { Series, VisualizationSettings } from "metabase-types/api";
export const getSeriesDisplays = (transformedSeries, settings) => {
return transformedSeries.map(single => settings.series(single).display);
export const getSeriesDisplays = (
series: Series,
settings: VisualizationSettings,
) => {
return series.map(single => settings.series(single).display);
};
export function getDefaultDimensionLabel(multipleSeries) {
export function getDefaultDimensionLabel(multipleSeries: Series) {
return getDefaultXAxisTitle(multipleSeries[0]?.data.cols[0]);
}
function canHaveDataLabels(series, vizSettings) {
function canHaveDataLabels(series: Series, vizSettings: VisualizationSettings) {
const areAllAreas = getSeriesDisplays(series, vizSettings).every(
display => display === "area",
);
return vizSettings["stackable.stack_type"] !== "normalized" || !areAllAreas;
}
export const GRAPH_DATA_SETTINGS = {
export const GRAPH_DATA_SETTINGS: VisualizationSettingsDefinitions = {
...columnSettings({
getColumns: ([
{
@@ -85,12 +90,12 @@ export const GRAPH_DATA_SETTINGS = {
? "0.5rem"
: "1rem",
isValid: (series, vizSettings) => {
const dimensions = vizSettings["graph.dimensions"] ?? [];
const dimensions = vizSettings["graph.dimensions"];
if (dimensions.length === 0) {
const defaultDimensions = getDefaultDimensions(series, vizSettings);
return defaultDimensions.length === 0;
} else {
return getAreDimensionsAndMetricsValid(series, vizSettings);
return getAreDimensionsAndMetricsValid(series);
}
},
getDefault: (series, vizSettings) =>
@@ -180,16 +185,17 @@ export const GRAPH_DATA_SETTINGS = {
section: t`Data`,
title: t`Y-axis`,
widget: "fields",
isValid: (series, vizSettings) => {
isValid: (series: Series, vizSettings: VisualizationSettings) => {
const metrics = vizSettings["graph.metrics"] ?? [];
if (metrics.length === 0) {
const defaultMetrics = getDefaultMetrics(series, vizSettings);
return defaultMetrics.length === 0;
} else {
return getAreDimensionsAndMetricsValid(series, vizSettings);
return getAreDimensionsAndMetricsValid(series);
}
},
getDefault: (series, vizSettings) => getDefaultMetrics(series, vizSettings),
getDefault: (series: Series, vizSettings: VisualizationSettings) =>
getDefaultMetrics(series, vizSettings),
persistDefault: true,
getProps: ([{ card, data }], vizSettings, _onChange, extra) => {
const options = data.cols
@@ -226,12 +232,12 @@ export const GRAPH_DATA_SETTINGS = {
...seriesSetting(),
};
export const GRAPH_BUBBLE_SETTINGS = {
export const GRAPH_BUBBLE_SETTINGS: VisualizationSettingsDefinitions = {
"scatter.bubble": {
section: t`Data`,
title: t`Bubble size`,
widget: "field",
isValid: (series, vizSettings) =>
isValid: series =>
series.some(({ card, data }) =>
columnsAreValid(
[card.visualization_settings["scatter.bubble"]],
@@ -240,7 +246,7 @@ export const GRAPH_BUBBLE_SETTINGS = {
),
),
getDefault: series => getDefaultColumns(series).bubble,
getProps: ([{ card, data }], vizSettings, onChange) => {
getProps: ([{ data }], vizSettings, onChange) => {
const options = data.cols.filter(isNumeric).map(getOptionFromColumn);
return {
options,
@@ -253,7 +259,7 @@ export const GRAPH_BUBBLE_SETTINGS = {
},
};
export const LINE_SETTINGS = {
export const LINE_SETTINGS: VisualizationSettingsDefinitions = {
// DEPRECATED: moved to series settings
"line.interpolate": {
default: "linear",
@@ -266,7 +272,7 @@ export const LINE_SETTINGS = {
},
};
export const STACKABLE_SETTINGS = {
export const STACKABLE_SETTINGS: VisualizationSettingsDefinitions = {
"stackable.stack_type": {
section: t`Display`,
title: t`Stacking`,
@@ -283,7 +289,7 @@ export const STACKABLE_SETTINGS = {
return isStackingValueValid(settings, seriesDisplays);
},
getDefault: ([{ card, data }], settings) => {
getDefault: ([{ card }], settings) => {
return getDefaultStackingValue(settings, card);
},
getHidden: (series, settings) => {
@@ -298,14 +304,14 @@ export const STACKABLE_SETTINGS = {
},
};
export const LEGEND_SETTINGS = {
export const LEGEND_SETTINGS: VisualizationSettingsDefinitions = {
"legend.is_reversed": {
getDefault: (_series, settings) => getDefaultLegendIsReversed(settings),
hidden: true,
},
};
export const TOOLTIP_SETTINGS = {
export const TOOLTIP_SETTINGS: VisualizationSettingsDefinitions = {
"graph.tooltip_type": {
getDefault: ([{ card }]) => {
const shouldShowComparisonTooltip = !["scatter", "waterfall"].includes(
@@ -344,13 +350,13 @@ export const TOOLTIP_SETTINGS = {
},
};
export const GRAPH_TREND_SETTINGS = {
export const GRAPH_TREND_SETTINGS: VisualizationSettingsDefinitions = {
"graph.show_trendline": {
section: t`Display`,
title: t`Trend line`,
widget: "toggle",
default: false,
getHidden: (series, vizSettings) => {
getHidden: series => {
const { insights } = series[0].data;
return !insights || insights.length === 0;
},
@@ -360,7 +366,7 @@ export const GRAPH_TREND_SETTINGS = {
},
};
export const GRAPH_DISPLAY_VALUES_SETTINGS = {
export const GRAPH_DISPLAY_VALUES_SETTINGS: VisualizationSettingsDefinitions = {
"graph.show_values": {
section: t`Display`,
title: t`Show values on data points`,
@@ -463,7 +469,7 @@ export const GRAPH_DISPLAY_VALUES_SETTINGS = {
// temporarily hiding the setting (metabase#50510)
default: Number.MAX_SAFE_INTEGER,
isValid: () => false,
getProps: ([{ card }], settings) => {
getProps: (_series, settings) => {
return {
isEnabled: settings["graph.max_categories_enabled"],
aggregationFunction: settings["graph.other_category_aggregation_fn"],
@@ -489,12 +495,12 @@ export const GRAPH_DISPLAY_VALUES_SETTINGS = {
},
};
export const GRAPH_COLORS_SETTINGS = {
export const GRAPH_COLORS_SETTINGS: VisualizationSettingsDefinitions = {
// DEPRECATED: replaced with "color" series setting
"graph.colors": {},
};
export const GRAPH_AXIS_SETTINGS = {
export const GRAPH_AXIS_SETTINGS: VisualizationSettingsDefinitions = {
"graph.x_axis._is_timeseries": {
readDependencies: ["graph.dimensions"],
getDefault: ([{ data }], vizSettings) =>
@@ -519,14 +525,11 @@ export const GRAPH_AXIS_SETTINGS = {
},
},
"graph.x_axis._is_histogram": {
getDefault: (
[
{
data: { cols },
},
],
vizSettings,
) => getDefaultIsHistogram(cols[0]),
getDefault: ([
{
data: { cols },
},
]) => getDefaultIsHistogram(cols[0]),
},
"graph.x_axis.scale": {
section: t`Axes`,
@@ -540,7 +543,7 @@ export const GRAPH_AXIS_SETTINGS = {
"graph.x_axis._is_histogram",
],
isValid: isXAxisScaleValid,
getDefault: (series, vizSettings) => getDefaultXAxisScale(vizSettings),
getDefault: (_series, vizSettings) => getDefaultXAxisScale(vizSettings),
getProps: (series, vizSettings) => ({
options: getAvailableXAxisScales(series, vizSettings),
}),
@@ -552,7 +555,7 @@ export const GRAPH_AXIS_SETTINGS = {
group: t`Y-axis`,
widget: "select",
default: "linear",
getProps: (series, vizSettings) => ({
getProps: () => ({
options: [
{ name: t`Linear`, value: "linear" },
{ name: t`Power`, value: "pow" },
@@ -627,7 +630,7 @@ export const GRAPH_AXIS_SETTINGS = {
title: t`Min`,
widget: "number",
default: 0,
getHidden: (series, vizSettings) =>
getHidden: (_series, vizSettings) =>
vizSettings["graph.y_axis.auto_range"] !== false,
},
"graph.y_axis.max": {
@@ -637,7 +640,7 @@ export const GRAPH_AXIS_SETTINGS = {
title: t`Max`,
widget: "number",
default: 100,
getHidden: (series, vizSettings) =>
getHidden: (_series, vizSettings) =>
vizSettings["graph.y_axis.auto_range"] !== false,
},
"graph.y_axis.auto_split": {
@@ -665,7 +668,7 @@ export const GRAPH_AXIS_SETTINGS = {
index: 2,
group: t`X-axis`,
widget: "input",
getHidden: (series, vizSettings) =>
getHidden: (_series, vizSettings) =>
vizSettings["graph.x_axis.labels_enabled"] === false,
getDefault: getDefaultDimensionLabel,
getProps: series => ({
@@ -687,7 +690,7 @@ export const GRAPH_AXIS_SETTINGS = {
index: 2,
group: t`Y-axis`,
widget: "input",
getHidden: (series, vizSettings) =>
getHidden: (_series, vizSettings) =>
vizSettings["graph.y_axis.labels_enabled"] === false,
getDefault: (series, vizSettings) => {
// If there are multiple series, we check if the metric names match.
@@ -695,7 +698,7 @@ export const GRAPH_AXIS_SETTINGS = {
const [metric] = vizSettings["graph.metrics"];
const metricNames = series.map(({ data: { cols } }) => {
const metricCol = cols.find(c => c.name === metric);
return metricCol && metricCol.display_name;
return metricCol ? metricCol.display_name : null;
});
return getDefaultYAxisTitle(metricNames);

View File

@@ -15,7 +15,10 @@ import {
getDefaultDimensionsAndMetrics,
preserveExistingColumnsOrder,
} from "metabase/visualizations/lib/utils";
import type { ComputedVisualizationSettings } from "metabase/visualizations/types";
import type {
ComputedVisualizationSettings,
GraphMetricName,
} from "metabase/visualizations/types";
import { getColumnKey } from "metabase-lib/v1/queries/utils/column-key";
import {
isAny,
@@ -29,6 +32,7 @@ import type {
DatasetColumn,
DatasetData,
RawSeries,
Series,
SeriesOrderSetting,
} from "metabase-types/api";
@@ -76,7 +80,7 @@ export function getDefaultDimensions(
export function getDefaultMetrics(
rawSeries: RawSeries,
settings: ComputedVisualizationSettings,
) {
): GraphMetricName[] {
const [{ card }] = rawSeries;
const prevMetrics = settings["graph.metrics"] ?? [];
const defaultMetrics = getDefaultColumns(rawSeries).metrics;
@@ -194,7 +198,7 @@ export const getSeriesOrderVisibilitySettings = (
}));
};
export const getDefaultYAxisTitle = (metricNames: string[]) => {
export const getDefaultYAxisTitle = (metricNames: GraphMetricName[]) => {
const metricsCount = new Set(metricNames).size;
return metricsCount === 1 ? metricNames[0] : null;
};
@@ -312,7 +316,7 @@ export const getAvailableXAxisScales = (
const WATERFALL_UNSUPPORTED_X_AXIS_SCALES = ["pow", "log"];
export const isXAxisScaleValid = (
series: RawSeries,
series: Series,
settings: ComputedVisualizationSettings,
) => {
const isWaterfall = series[0].card.display === "waterfall";
@@ -325,9 +329,9 @@ export const isXAxisScaleValid = (
return false;
}
return (
return Boolean(
!isWaterfall ||
(xAxisScale && !WATERFALL_UNSUPPORTED_X_AXIS_SCALES.includes(xAxisScale))
(xAxisScale && !WATERFALL_UNSUPPORTED_X_AXIS_SCALES.includes(xAxisScale)),
);
};
@@ -369,7 +373,11 @@ export function getDefaultBubbleSizeCol(data: DatasetData) {
return getDefaultScatterColumns(data).bubble;
}
export function getDefaultColumns(series: RawSeries) {
export function getDefaultColumns(series: RawSeries): {
dimensions: (string | null)[];
metrics: GraphMetricName[];
bubble?: string | null;
} {
if (series[0].card.display === "scatter") {
return getDefaultScatterColumns(series[0].data);
} else {

View File

@@ -51,13 +51,10 @@ export const getDefaultShowLegend = () => true;
export const getDefaultShowTotal = () => true;
export function getDefaultShowLabels(settings: ComputedVisualizationSettings) {
if (getPieDimensions(settings).length <= 1) {
return false;
}
return true;
return getPieDimensions(settings).length > 1;
}
export const getDefaultPercentVisibility = () => "legend";
export const getDefaultPercentVisibility = () => "legend" as const;
export const getDefaultSliceThreshold = () => SLICE_THRESHOLD * 100;

View File

@@ -1,4 +1,4 @@
import type { ReactNode } from "react";
import type { ComponentType, ReactNode } from "react";
import type { OptionsType } from "metabase/lib/formatting/types";
import type { IconName, IconProps } from "metabase/ui";
@@ -19,6 +19,7 @@ import type {
Card,
Dashboard,
DashboardCard,
DashboardId,
DatasetColumn,
DatasetData,
RawSeries,
@@ -98,6 +99,8 @@ export interface StaticVisualizationProps {
isStorybook?: boolean;
}
export type GraphMetricName = string | null;
export interface VisualizationProps {
series: Series;
dashboard?: Dashboard;
@@ -157,6 +160,9 @@ export interface VisualizationProps {
onDeselectTimelineEvents?: () => void;
onOpenTimelines?: () => void;
"graph.dimensions"?: string[];
"graph.metrics"?: GraphMetricName[];
canRemoveSeries?: (seriesIndex: number) => boolean;
canToggleSeriesVisibility?: boolean;
onRemoveSeries?: (event: MouseEvent, seriesIndex: number) => void;
@@ -165,6 +171,11 @@ export interface VisualizationProps {
dispatch: Dispatch;
}
export type CardDerivedSettingsData = {
transformedSeries?: TransformedSeries;
dashboardId?: DashboardId;
};
export type VisualizationPassThroughProps = {
// frontend/src/metabase/query_builder/components/VisualizationResult.jsx
canToggleSeriesVisibility?: boolean;
@@ -227,14 +238,21 @@ export type ColumnSettingDefinition<TValue, TProps = unknown> = {
) => TProps;
};
export type VisualizationSettingDefinition<TValue, TProps = void> = {
type BaseVisualizationSettingDefinition<TValue> = {
section?: string;
title?: string;
group?: string;
widget?: string | React.ComponentType<TProps>;
isValid?: (series: Series, settings: VisualizationSettings) => boolean;
getHidden?: (series: Series, settings: VisualizationSettings) => boolean;
getDefault?: (series: Series, settings: VisualizationSettings) => TValue;
getHidden?: (
series: Series,
settings: VisualizationSettings,
extra?: CardDerivedSettingsData,
) => boolean;
getDefault?: (
series: Series,
settings: VisualizationSettings,
) => TValue | null;
onUpdate?: (value: TValue, extra: CardDerivedSettingsData) => void;
getValue?: (series: Series, settings: VisualizationSettings) => TValue;
getDisabled?: (series: Series, settings: VisualizationSettings) => TValue;
disabled?: boolean;
@@ -243,24 +261,48 @@ export type VisualizationSettingDefinition<TValue, TProps = void> = {
getMarginBottom?: (series: Series, settings: VisualizationSettings) => string;
persistDefault?: boolean;
inline?: boolean;
props?: TProps;
getProps?: (
series: Series,
vizSettings: VisualizationSettings,
onChange: (value: TValue) => void,
extra: unknown,
onChangeSettings: (value: Record<string, any>) => void,
) => TProps;
readDependencies?: string[];
writeDependencies?: string[];
eraseDependencies?: string[];
// is the setting visible in the dashboard card viz settings
dashboard?: boolean;
useRawSeries?: boolean;
hidden?: boolean;
placeholder?: string;
index?: number;
};
export type WidgetComponentDef<Widget, Props, Value> = {
widget?: Widget;
props?: Props;
getProps?: (
series: Series,
vizSettings: VisualizationSettings,
onChange: (value: Value | null) => void,
extra: CardDerivedSettingsData,
onChangeSettings: (value: VisualizationSettings) => void,
) => Props;
};
type VisualizationSettingWidgetDef<
Value,
Widget extends string | ComponentType<any> = string | ComponentType<any>,
> = Widget extends string
? WidgetComponentDef<Widget, unknown, Value>
: Widget extends ComponentType<infer Props>
? WidgetComponentDef<Widget, Props, Value>
: never;
export type VisualizationSettingDefinition<
K extends keyof VisualizationSettings = keyof VisualizationSettings,
Widget extends string | ComponentType<any> = string | ComponentType<any>,
> = {
id?: K;
} & BaseVisualizationSettingDefinition<VisualizationSettings[K]> &
VisualizationSettingWidgetDef<VisualizationSettings[K], Widget>;
export type VisualizationSettingsDefinitions = {
[key: string]: VisualizationSettingDefinition<unknown, unknown>;
[K in keyof VisualizationSettings]: VisualizationSettingDefinition<K>;
};
export type VisualizationGridSize = {

View File

@@ -10,10 +10,7 @@ import {
getCartesianChartDefinition,
} from "metabase/visualizations/visualizations/CartesianChart/chart-definition";
import type {
VisualizationProps,
VisualizationSettingsDefinitions,
} from "../../types";
import type { VisualizationProps } from "../../types";
Object.assign(
AreaChart,
@@ -26,7 +23,7 @@ Object.assign(
defaultSize: getDefaultSize("area"),
settings: {
...COMBO_CHARTS_SETTINGS_DEFINITIONS,
} as any as VisualizationSettingsDefinitions,
},
}),
);

View File

@@ -10,10 +10,7 @@ import {
getCartesianChartDefinition,
} from "metabase/visualizations/visualizations/CartesianChart/chart-definition";
import type {
VisualizationProps,
VisualizationSettingsDefinitions,
} from "../../types";
import type { VisualizationProps } from "../../types";
Object.assign(
BarChart,
@@ -26,7 +23,7 @@ Object.assign(
defaultSize: getDefaultSize("bar"),
settings: {
...COMBO_CHARTS_SETTINGS_DEFINITIONS,
} as any as VisualizationSettingsDefinitions,
},
}),
);

View File

@@ -106,15 +106,16 @@ export const getCartesianChartDefinition = (
};
};
export const COMBO_CHARTS_SETTINGS_DEFINITIONS = {
...STACKABLE_SETTINGS,
...LINE_SETTINGS,
...GRAPH_GOAL_SETTINGS,
...GRAPH_TREND_SETTINGS,
...GRAPH_COLORS_SETTINGS,
...GRAPH_AXIS_SETTINGS,
...GRAPH_DISPLAY_VALUES_SETTINGS,
...GRAPH_DATA_SETTINGS,
...TOOLTIP_SETTINGS,
...LEGEND_SETTINGS,
} as any as VisualizationSettingsDefinitions;
export const COMBO_CHARTS_SETTINGS_DEFINITIONS: VisualizationSettingsDefinitions =
{
...STACKABLE_SETTINGS,
...LINE_SETTINGS,
...GRAPH_GOAL_SETTINGS,
...GRAPH_TREND_SETTINGS,
...GRAPH_COLORS_SETTINGS,
...GRAPH_AXIS_SETTINGS,
...GRAPH_DISPLAY_VALUES_SETTINGS,
...GRAPH_DATA_SETTINGS,
...TOOLTIP_SETTINGS,
...LEGEND_SETTINGS,
};

View File

@@ -10,10 +10,7 @@ import {
getCartesianChartDefinition,
} from "metabase/visualizations/visualizations/CartesianChart/chart-definition";
import type {
VisualizationProps,
VisualizationSettingsDefinitions,
} from "../../types";
import type { VisualizationProps } from "../../types";
Object.assign(
ComboChart,
@@ -26,7 +23,7 @@ Object.assign(
defaultSize: getDefaultSize("combo"),
settings: {
...COMBO_CHARTS_SETTINGS_DEFINITIONS,
} as any as VisualizationSettingsDefinitions,
},
}),
);

View File

@@ -10,10 +10,7 @@ import {
getCartesianChartDefinition,
} from "metabase/visualizations/visualizations/CartesianChart/chart-definition";
import type {
VisualizationProps,
VisualizationSettingsDefinitions,
} from "../../types";
import type { VisualizationProps } from "../../types";
Object.assign(
LineChart,
@@ -26,7 +23,7 @@ Object.assign(
defaultSize: getDefaultSize("line"),
settings: {
...COMBO_CHARTS_SETTINGS_DEFINITIONS,
} as any as VisualizationSettingsDefinitions,
},
}),
);

View File

@@ -12,10 +12,7 @@ import {
getDefaultSize,
getMinSize,
} from "metabase/visualizations/shared/utils/sizes";
import type {
ComputedVisualizationSettings,
VisualizationSettingsDefinitions,
} from "metabase/visualizations/types";
import type { ComputedVisualizationSettings } from "metabase/visualizations/types";
import { isDate, isDimension, isMetric } from "metabase-lib/v1/types/utils/isa";
import type { DatasetData, RawSeries, Series } from "metabase-types/api";
@@ -211,5 +208,5 @@ export const SANKEY_CHART_DEFINITION = {
},
settings: {
...SETTINGS_DEFINITIONS,
} as any as VisualizationSettingsDefinitions,
},
};

View File

@@ -16,10 +16,7 @@ import {
GRAPH_TREND_SETTINGS,
TOOLTIP_SETTINGS,
} from "../../lib/settings/graph";
import type {
VisualizationProps,
VisualizationSettingsDefinitions,
} from "../../types";
import type { VisualizationProps } from "../../types";
Object.assign(
ScatterPlot,
@@ -38,7 +35,7 @@ Object.assign(
...GRAPH_AXIS_SETTINGS,
...GRAPH_DATA_SETTINGS,
...TOOLTIP_SETTINGS,
} as any as VisualizationSettingsDefinitions,
},
}),
);

View File

@@ -14,7 +14,6 @@ import {
import type {
ComputedVisualizationSettings,
VisualizationProps,
VisualizationSettingsDefinitions,
} from "metabase/visualizations/types";
import { CartesianChart } from "../CartesianChart";
@@ -64,7 +63,7 @@ Object.assign(
...GRAPH_DISPLAY_VALUES_SETTINGS,
...GRAPH_DATA_SETTINGS,
...TOOLTIP_SETTINGS,
} as any as VisualizationSettingsDefinitions,
},
}),
);