Compare commits
1 Commits
python-run
...
remove-tra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d82e8722a0 |
@@ -120,8 +120,6 @@ export type SingleSeries = {
|
||||
} & Pick<Dataset, "data" | "error">;
|
||||
|
||||
export type RawSeries = SingleSeries[];
|
||||
export type TransformedSeries = RawSeries & { _raw: Series };
|
||||
export type Series = RawSeries | TransformedSeries;
|
||||
|
||||
export type TemplateTagId = string;
|
||||
export type TemplateTagName = string;
|
||||
|
||||
@@ -12,7 +12,7 @@ import * as Lib from "metabase-lib";
|
||||
import { MetabaseApi } from "metabase/services";
|
||||
import {
|
||||
extractRemappings,
|
||||
getVisualizationTransformed,
|
||||
getVisualizationDefinition,
|
||||
} from "metabase/visualizations";
|
||||
import { getComputedSettingsForSeries } from "metabase/visualizations/lib/settings/visualization";
|
||||
|
||||
@@ -717,7 +717,7 @@ export const getRawSeries = createSelector(
|
||||
const _getVisualizationTransformed = createSelector(
|
||||
[getRawSeries],
|
||||
rawSeries =>
|
||||
rawSeries && getVisualizationTransformed(extractRemappings(rawSeries)),
|
||||
rawSeries && getVisualizationDefinition(extractRemappings(rawSeries)),
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -185,8 +185,7 @@ export const computeStaticComboChartSettings = (
|
||||
);
|
||||
|
||||
const seriesDisplays = seriesModels.map(
|
||||
seriesModel =>
|
||||
settings.series(seriesModel.legacySeriesSettingsObjectKey).display,
|
||||
seriesModel => settings.series(seriesModel).display,
|
||||
);
|
||||
|
||||
fillWithDefaultValue(
|
||||
|
||||
@@ -3,16 +3,12 @@ import { useCallback } from "react";
|
||||
|
||||
import type { IconProps } from "metabase/ui";
|
||||
import type { OnChangeCardAndRun } from "metabase/visualizations/types";
|
||||
import type {
|
||||
Series,
|
||||
TransformedSeries,
|
||||
VisualizationSettings,
|
||||
} from "metabase-types/api";
|
||||
import type { RawSeries, VisualizationSettings } from "metabase-types/api";
|
||||
|
||||
import { ChartCaptionRoot } from "./ChartCaption.styled";
|
||||
|
||||
interface ChartCaptionProps {
|
||||
series: Series;
|
||||
series: RawSeries;
|
||||
settings: VisualizationSettings;
|
||||
icon?: IconProps;
|
||||
actionButtons?: ReactNode;
|
||||
@@ -32,9 +28,8 @@ const ChartCaption = ({
|
||||
}: ChartCaptionProps) => {
|
||||
const title = settings["card.title"] ?? series[0].card.name;
|
||||
const description = settings["card.description"];
|
||||
const data = (series as TransformedSeries)._raw || series;
|
||||
const card = data[0].card;
|
||||
const cardIds = new Set(data.map(s => s.card.id));
|
||||
const card = series[0].card;
|
||||
const cardIds = new Set(series.map(s => s.card.id));
|
||||
const canSelectTitle = cardIds.size === 1 && onChangeCardAndRun;
|
||||
|
||||
const handleSelectTitle = useCallback(() => {
|
||||
|
||||
@@ -9,10 +9,7 @@ import Button from "metabase/core/components/Button";
|
||||
import Radio from "metabase/core/components/Radio";
|
||||
import CS from "metabase/css/core/index.css";
|
||||
import * as MetabaseAnalytics from "metabase/lib/analytics";
|
||||
import {
|
||||
getVisualizationTransformed,
|
||||
extractRemappings,
|
||||
} from "metabase/visualizations";
|
||||
import { extractRemappings } from "metabase/visualizations";
|
||||
import Visualization from "metabase/visualizations/components/Visualization";
|
||||
import { updateSeriesColor } from "metabase/visualizations/lib/series";
|
||||
import {
|
||||
@@ -22,8 +19,10 @@ import {
|
||||
getSettingsWidgets,
|
||||
} from "metabase/visualizations/lib/settings";
|
||||
import { getSettingDefinitionsForColumn } from "metabase/visualizations/lib/settings/column";
|
||||
import { keyForSingleSeries } from "metabase/visualizations/lib/settings/series";
|
||||
import { getSettingsWidgetsForSeries } from "metabase/visualizations/lib/settings/visualization";
|
||||
import {
|
||||
getSettingsWidgetsForSeries,
|
||||
getSettingsModelForSeries,
|
||||
} from "metabase/visualizations/lib/settings/visualization";
|
||||
import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
|
||||
|
||||
import {
|
||||
@@ -162,11 +161,13 @@ class ChartSettings extends Component {
|
||||
} else {
|
||||
const { isDashboard, dashboard } = this.props;
|
||||
const transformedSeries = this._getTransformedSeries();
|
||||
const settingsModel = this._getSettingsModel();
|
||||
|
||||
return getSettingsWidgetsForSeries(
|
||||
transformedSeries,
|
||||
this.handleChangeSettings,
|
||||
isDashboard,
|
||||
settingsModel,
|
||||
{ dashboardId: dashboard?.id },
|
||||
);
|
||||
}
|
||||
@@ -185,16 +186,20 @@ class ChartSettings extends Component {
|
||||
}
|
||||
_getTransformedSeries() {
|
||||
const rawSeries = this._getRawSeries();
|
||||
const { series: transformedSeries } = getVisualizationTransformed(
|
||||
extractRemappings(rawSeries),
|
||||
);
|
||||
return transformedSeries;
|
||||
return extractRemappings(rawSeries);
|
||||
}
|
||||
|
||||
_getSettingsModel() {
|
||||
const { series } = this.props;
|
||||
const settings = this._getSettings() || {};
|
||||
return getSettingsModelForSeries(series, settings);
|
||||
}
|
||||
|
||||
columnHasSettings(col) {
|
||||
const { series } = this.props;
|
||||
const settings = this._getSettings() || {};
|
||||
const settingsDefs = getSettingDefinitionsForColumn(series, col);
|
||||
const settingsModel = this._getSettingsModel();
|
||||
const computedSettings = getComputedSettings(settingsDefs, col, settings);
|
||||
|
||||
return getSettingsWidgets(
|
||||
@@ -203,6 +208,7 @@ class ChartSettings extends Component {
|
||||
computedSettings,
|
||||
col,
|
||||
_.noop,
|
||||
settingsModel,
|
||||
{
|
||||
series,
|
||||
},
|
||||
@@ -243,15 +249,16 @@ class ChartSettings extends Component {
|
||||
}
|
||||
});
|
||||
|
||||
if (singleSeriesForColumn) {
|
||||
return {
|
||||
...seriesSettingsWidget,
|
||||
props: {
|
||||
...seriesSettingsWidget.props,
|
||||
initialKey: keyForSingleSeries(singleSeriesForColumn),
|
||||
},
|
||||
};
|
||||
}
|
||||
// TODO: fix and uncomment
|
||||
// if (singleSeriesForColumn) {
|
||||
// return {
|
||||
// ...seriesSettingsWidget,
|
||||
// props: {
|
||||
// ...seriesSettingsWidget.props,
|
||||
// initialKey: keyForSingleSeries(singleSeriesForColumn),
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -50,6 +50,7 @@ function getWidgets({
|
||||
onChangeSetting(changedSettings);
|
||||
}
|
||||
},
|
||||
null,
|
||||
{ series, ...extraData },
|
||||
);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import { getIsEmbeddingSdk } from "metabase/selectors/embed";
|
||||
import { getFont } from "metabase/styled-components/selectors";
|
||||
import {
|
||||
extractRemappings,
|
||||
getVisualizationTransformed,
|
||||
getVisualizationDefinition,
|
||||
} from "metabase/visualizations";
|
||||
import { Mode } from "metabase/visualizations/click-actions/Mode";
|
||||
import { getMode } from "metabase/visualizations/click-actions/lib/modes";
|
||||
@@ -145,10 +145,10 @@ class Visualization extends PureComponent {
|
||||
|
||||
transform(newProps) {
|
||||
const transformed = newProps.rawSeries
|
||||
? getVisualizationTransformed(extractRemappings(newProps.rawSeries))
|
||||
? getVisualizationDefinition(extractRemappings(newProps.rawSeries))
|
||||
: null;
|
||||
const series = transformed && transformed.series;
|
||||
const visualization = transformed && transformed.visualization;
|
||||
const series = transformed?.series;
|
||||
const visualization = transformed?.visualization;
|
||||
const computedSettings = !this.isLoading(series)
|
||||
? getComputedSettingsForSeries(series)
|
||||
: {};
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { t } from "ttag";
|
||||
import _ from "underscore";
|
||||
|
||||
import { keyForSingleSeries } from "metabase/visualizations/lib/settings/series";
|
||||
import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
|
||||
|
||||
import {
|
||||
@@ -43,9 +42,10 @@ const ChartSettingFieldPicker = ({
|
||||
const metricColumn = single.data.cols[1];
|
||||
return getColumnKey(metricColumn) === columnKey;
|
||||
});
|
||||
if (seriesForColumn) {
|
||||
seriesKey = keyForSingleSeries(seriesForColumn);
|
||||
}
|
||||
// TODO: fix and uncomment
|
||||
// if (seriesForColumn) {
|
||||
// seriesKey = keyForSingleSeries(seriesForColumn);
|
||||
// }
|
||||
}
|
||||
return (
|
||||
<ChartSettingFieldPickerRoot
|
||||
|
||||
@@ -67,7 +67,7 @@ const chartSettingNestedSettings =
|
||||
};
|
||||
|
||||
render() {
|
||||
const { series, objects, extra } = this.props;
|
||||
const { series, objects, extra, settingsModel } = this.props;
|
||||
const editingObjectKey = this.getEditingObjectKey();
|
||||
if (editingObjectKey !== undefined) {
|
||||
const editingObject = _.find(
|
||||
@@ -82,6 +82,7 @@ const chartSettingNestedSettings =
|
||||
editingObject,
|
||||
objectSettings,
|
||||
this.handleChangeSettingsForEditingObject,
|
||||
settingsModel,
|
||||
extra,
|
||||
);
|
||||
return (
|
||||
|
||||
@@ -418,9 +418,7 @@ export const getChartPadding = (
|
||||
// We handle non-categorical scatter plots differently, because echarts places
|
||||
// the tick labels on the very edge of the x-axis for scatter plots only.
|
||||
const isScatterPlot = chartModel.seriesModels.some(seriesModel => {
|
||||
const seriesSettings = settings.series(
|
||||
seriesModel.legacySeriesSettingsObjectKey,
|
||||
);
|
||||
const seriesSettings = settings.series(seriesModel);
|
||||
return seriesSettings.display === "scatter";
|
||||
});
|
||||
if (isScatterPlot && chartModel.xAxisModel.axisType !== "category") {
|
||||
|
||||
@@ -284,9 +284,7 @@ const getYAxisSplit = (
|
||||
}
|
||||
|
||||
const axisBySeriesKey = seriesModels.reduce((acc, seriesModel) => {
|
||||
const seriesSettings: SeriesSettings = settings.series(
|
||||
seriesModel.legacySeriesSettingsObjectKey,
|
||||
);
|
||||
const seriesSettings: SeriesSettings = settings.series(seriesModel);
|
||||
|
||||
const seriesStack = stackModels.find(stackModel =>
|
||||
stackModel.seriesKeys.includes(seriesModel.dataKey),
|
||||
|
||||
@@ -281,10 +281,7 @@ export const getNullReplacerTransform = (
|
||||
): TransformFn => {
|
||||
const replaceNullsWithZeroDataKeys = seriesModels
|
||||
.filter(
|
||||
seriesModel =>
|
||||
settings.series(seriesModel.legacySeriesSettingsObjectKey)[
|
||||
"line.missing"
|
||||
] === "zero",
|
||||
seriesModel => settings.series(seriesModel)["line.missing"] === "zero",
|
||||
)
|
||||
.map(seriesModel => seriesModel.dataKey);
|
||||
|
||||
@@ -302,9 +299,7 @@ const hasInterpolatedAreaSeries = (
|
||||
settings: ComputedVisualizationSettings,
|
||||
) => {
|
||||
return seriesModels.some(seriesModel => {
|
||||
const seriesSettings = settings.series(
|
||||
seriesModel.legacySeriesSettingsObjectKey,
|
||||
);
|
||||
const seriesSettings = settings.series(seriesModel);
|
||||
return (
|
||||
seriesSettings["line.missing"] !== "none" &&
|
||||
seriesSettings.display === "area"
|
||||
@@ -700,9 +695,7 @@ export const applyVisualizationSettingsDataTransformations = (
|
||||
showWarning?: ShowWarning,
|
||||
) => {
|
||||
const barSeriesModels = seriesModels.filter(seriesModel => {
|
||||
const seriesSettings = settings.series(
|
||||
seriesModel.legacySeriesSettingsObjectKey,
|
||||
);
|
||||
const seriesSettings = settings.series(seriesModel);
|
||||
return seriesSettings.display === "bar";
|
||||
});
|
||||
const seriesDataKeys = seriesModels.map(seriesModel => seriesModel.dataKey);
|
||||
|
||||
@@ -121,7 +121,7 @@ export const getCardsSeriesModels = (
|
||||
rawSeries: RawSeries,
|
||||
cardsColumns: CartesianChartColumns[],
|
||||
settings: ComputedVisualizationSettings,
|
||||
renderingContext: RenderingContext,
|
||||
renderingContext: Pick<RenderingContext, "formatValue">,
|
||||
) => {
|
||||
const hasMultipleCards = rawSeries.length > 1;
|
||||
return rawSeries.flatMap((cardDataset, index) => {
|
||||
@@ -155,7 +155,7 @@ export const getCardSeriesModels = (
|
||||
hasMultipleCards: boolean,
|
||||
isFirstCard: boolean,
|
||||
settings: ComputedVisualizationSettings,
|
||||
renderingContext: RenderingContext,
|
||||
renderingContext: Pick<RenderingContext, "formatValue">,
|
||||
): SeriesModel[] => {
|
||||
const cardId = card.id ?? null;
|
||||
const hasBreakout = "breakout" in columns;
|
||||
@@ -535,9 +535,7 @@ export function getDisplaySeriesSettingsByDataKey(
|
||||
settings: ComputedVisualizationSettings,
|
||||
) {
|
||||
const seriesSettingsByKey = seriesModels.reduce((acc, seriesModel) => {
|
||||
acc[seriesModel.dataKey] = settings.series(
|
||||
seriesModel.legacySeriesSettingsObjectKey,
|
||||
);
|
||||
acc[seriesModel.dataKey] = settings.series(seriesModel);
|
||||
return acc;
|
||||
}, {} as Record<DataKey, SeriesSettings>);
|
||||
|
||||
@@ -700,8 +698,7 @@ const getSeriesLabelsFormatters = (
|
||||
}
|
||||
|
||||
const seriesModelsWithLabels = seriesModels.filter(seriesModel => {
|
||||
const seriesSettings =
|
||||
settings.series(seriesModel.legacySeriesSettingsObjectKey) ?? {};
|
||||
const seriesSettings = settings.series(seriesModel) ?? {};
|
||||
|
||||
return !!seriesSettings["show_series_values"];
|
||||
});
|
||||
|
||||
@@ -15,8 +15,7 @@ export const getStackModels = (
|
||||
|
||||
const seriesModelsByDisplay = _.groupBy(
|
||||
seriesModels,
|
||||
seriesModel =>
|
||||
settings.series(seriesModel.legacySeriesSettingsObjectKey).display,
|
||||
seriesModel => settings.series(seriesModel).display,
|
||||
);
|
||||
|
||||
return getObjectKeys(seriesModelsByDisplay)
|
||||
@@ -29,9 +28,7 @@ export const getStackModels = (
|
||||
axis = "left";
|
||||
} else {
|
||||
axis = stackSeriesModels.every(
|
||||
seriesModel =>
|
||||
settings.series(seriesModel.legacySeriesSettingsObjectKey)?.axis ===
|
||||
"right",
|
||||
seriesModel => settings.series(seriesModel)?.axis === "right",
|
||||
)
|
||||
? "right"
|
||||
: "left";
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { t } from "ttag";
|
||||
import _ from "underscore";
|
||||
|
||||
import type {
|
||||
DatasetData,
|
||||
Series,
|
||||
TransformedSeries,
|
||||
} from "metabase-types/api";
|
||||
import type { DatasetData, RawSeries } from "metabase-types/api";
|
||||
|
||||
import type { RemappingHydratedDatasetColumn } from "./types";
|
||||
import type { Visualization } from "./types/visualization";
|
||||
@@ -64,35 +60,8 @@ export function getVisualizationRaw(series: SeriesLike) {
|
||||
return visualizations.get(series[0].card.display);
|
||||
}
|
||||
|
||||
export function getVisualizationTransformed(series: TransformedSeries) {
|
||||
// don't transform if we don't have the data
|
||||
if (
|
||||
_.any(series, s => s.data == null) ||
|
||||
_.any(series, s => s.error != null)
|
||||
) {
|
||||
return {
|
||||
series,
|
||||
visualization: getVisualizationRaw(series),
|
||||
};
|
||||
}
|
||||
|
||||
// if a visualization has a transformSeries function, do the transformation until it returns the same visualization / series
|
||||
let visualization, lastSeries;
|
||||
do {
|
||||
visualization = visualizations.get(series[0].card.display);
|
||||
if (!visualization) {
|
||||
throw new Error(t`No visualization for ${series[0].card.display}`);
|
||||
}
|
||||
lastSeries = series;
|
||||
if (typeof visualization.transformSeries === "function") {
|
||||
series = visualization.transformSeries(series);
|
||||
}
|
||||
if (series !== lastSeries) {
|
||||
series = Object.assign([...series], { _raw: lastSeries });
|
||||
}
|
||||
} while (series !== lastSeries);
|
||||
|
||||
return { series, visualization };
|
||||
export function getVisualizationDefinition(series: RawSeries) {
|
||||
return { series, visualization: visualizations.get(series[0].card.display) };
|
||||
}
|
||||
|
||||
export function getIconForVisualizationType(display: string) {
|
||||
@@ -100,7 +69,7 @@ export function getIconForVisualizationType(display: string) {
|
||||
return viz?.iconName ?? "unknown";
|
||||
}
|
||||
|
||||
export const extractRemappings = (series: Series) => {
|
||||
export const extractRemappings = (series: RawSeries) => {
|
||||
const se = series.map(s => ({
|
||||
...s,
|
||||
data: s.data && extractRemappedColumns(s.data),
|
||||
|
||||
@@ -54,12 +54,11 @@ function canDisplayNull(settings) {
|
||||
|
||||
export function getXValues({ settings, series }) {
|
||||
// if _raw isn't set then we already have the raw series
|
||||
const { _raw: rawSeries = series } = series;
|
||||
const warn = () => {}; // no op since warning in handled by getDatas
|
||||
const uniqueValues = new Set();
|
||||
let isAscending = true;
|
||||
let isDescending = true;
|
||||
for (const { data } of rawSeries) {
|
||||
for (const { data } of series) {
|
||||
// In the raw series, the dimension isn't necessarily in the first element
|
||||
// of each row. This finds the correct column index.
|
||||
const columnIndex = getColumnIndex({ settings, data });
|
||||
|
||||
@@ -30,11 +30,17 @@ const WIDGETS = {
|
||||
colors: ChartSettingColorsPicker,
|
||||
};
|
||||
|
||||
export function getComputedSettings(
|
||||
settingsDefs,
|
||||
object,
|
||||
storedSettings,
|
||||
extra = {},
|
||||
export function getComputedSettings<
|
||||
TObject,
|
||||
TObjectSettings,
|
||||
TSettingsModel,
|
||||
TExtra,
|
||||
>(
|
||||
settingsDefs: $TODO,
|
||||
object: TObject,
|
||||
storedSettings: TObjectSettings,
|
||||
settingsModel: TSettingsModel,
|
||||
extra: TExtra = {},
|
||||
) {
|
||||
const computedSettings = {};
|
||||
for (const settingId in settingsDefs) {
|
||||
@@ -44,6 +50,7 @@ export function getComputedSettings(
|
||||
settingId,
|
||||
object,
|
||||
storedSettings,
|
||||
settingsModel,
|
||||
extra,
|
||||
);
|
||||
}
|
||||
@@ -56,6 +63,7 @@ function getComputedSetting(
|
||||
settingId,
|
||||
object,
|
||||
storedSettings,
|
||||
settingsModel,
|
||||
extra = {},
|
||||
) {
|
||||
if (settingId in computedSettings) {
|
||||
@@ -71,44 +79,55 @@ function getComputedSetting(
|
||||
dependentId,
|
||||
object,
|
||||
storedSettings,
|
||||
settingsModel,
|
||||
extra,
|
||||
);
|
||||
}
|
||||
|
||||
if (settingDef.useRawSeries && object._raw) {
|
||||
object = object._raw;
|
||||
}
|
||||
|
||||
const settings = { ...storedSettings, ...computedSettings };
|
||||
|
||||
try {
|
||||
if (settingDef.getValue) {
|
||||
return (computedSettings[settingId] = settingDef.getValue(
|
||||
computedSettings[settingId] = settingDef.getValue(
|
||||
object,
|
||||
settings,
|
||||
settingsModel,
|
||||
extra,
|
||||
));
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (storedSettings[settingId] !== undefined) {
|
||||
if (!settingDef.isValid || settingDef.isValid(object, settings, extra)) {
|
||||
return (computedSettings[settingId] = storedSettings[settingId]);
|
||||
if (
|
||||
!settingDef.isValid ||
|
||||
settingDef.isValid(object, settings, settingsModel, extra)
|
||||
) {
|
||||
computedSettings[settingId] = storedSettings[settingId];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (settingDef.getDefault) {
|
||||
const defaultValue = settingDef.getDefault(object, settings, extra);
|
||||
const defaultValue = settingDef.getDefault(
|
||||
object,
|
||||
settings,
|
||||
settingsModel,
|
||||
extra,
|
||||
);
|
||||
|
||||
return (computedSettings[settingId] = defaultValue);
|
||||
computedSettings[settingId] = defaultValue;
|
||||
return;
|
||||
}
|
||||
|
||||
if ("default" in settingDef) {
|
||||
return (computedSettings[settingId] = settingDef.default);
|
||||
computedSettings[settingId] = settingDef.default;
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Error getting setting", settingId, e);
|
||||
}
|
||||
return (computedSettings[settingId] = undefined);
|
||||
|
||||
computedSettings[settingId] = undefined;
|
||||
}
|
||||
|
||||
function getSettingWidget(
|
||||
@@ -118,6 +137,7 @@ function getSettingWidget(
|
||||
computedSettings,
|
||||
object,
|
||||
onChangeSettings,
|
||||
settingsModel,
|
||||
extra = {},
|
||||
) {
|
||||
const settingDef = settingDefs[settingId];
|
||||
@@ -133,33 +153,42 @@ function getSettingWidget(
|
||||
onChangeSettings(newSettings, question);
|
||||
settingDef.onUpdate?.(value, extra);
|
||||
};
|
||||
if (settingDef.useRawSeries && object._raw) {
|
||||
extra.transformedSeries = object;
|
||||
object = object._raw;
|
||||
}
|
||||
|
||||
return {
|
||||
...settingDef,
|
||||
id: settingId,
|
||||
value: value,
|
||||
section: settingDef.getSection
|
||||
? settingDef.getSection(object, computedSettings, extra)
|
||||
? settingDef.getSection(object, computedSettings, settingsModel, extra)
|
||||
: settingDef.section,
|
||||
title: settingDef.getTitle
|
||||
? settingDef.getTitle(object, computedSettings, extra)
|
||||
? settingDef.getTitle(object, computedSettings, settingsModel, extra)
|
||||
: settingDef.title,
|
||||
hidden: settingDef.getHidden
|
||||
? settingDef.getHidden(object, computedSettings, extra)
|
||||
? settingDef.getHidden(object, computedSettings, settingsModel, extra)
|
||||
: settingDef.hidden || false,
|
||||
marginBottom: settingDef.getMarginBottom
|
||||
? settingDef.getMarginBottom(object, computedSettings, extra)
|
||||
? settingDef.getMarginBottom(
|
||||
object,
|
||||
computedSettings,
|
||||
settingsModel,
|
||||
extra,
|
||||
)
|
||||
: settingDef.marginBottom,
|
||||
disabled: settingDef.getDisabled
|
||||
? settingDef.getDisabled(object, computedSettings, extra)
|
||||
? settingDef.getDisabled(object, computedSettings, settingsModel, extra)
|
||||
: settingDef.disabled || false,
|
||||
props: {
|
||||
settingsModel,
|
||||
...(settingDef.props ? settingDef.props : {}),
|
||||
...(settingDef.getProps
|
||||
? settingDef.getProps(object, computedSettings, onChange, extra)
|
||||
? settingDef.getProps(
|
||||
object,
|
||||
computedSettings,
|
||||
onChange,
|
||||
settingsModel,
|
||||
extra,
|
||||
)
|
||||
: {}),
|
||||
},
|
||||
set: settingId in storedSettings,
|
||||
@@ -172,13 +201,19 @@ function getSettingWidget(
|
||||
};
|
||||
}
|
||||
|
||||
export function getSettingsWidgets(
|
||||
settingDefs,
|
||||
storedSettings,
|
||||
computedSettings,
|
||||
object,
|
||||
onChangeSettings,
|
||||
extra = {},
|
||||
export function getSettingsWidgets<
|
||||
TObject,
|
||||
TObjectSettings,
|
||||
TSettingsModel,
|
||||
TExtra,
|
||||
>(
|
||||
settingDefs: $TODO,
|
||||
storedSettings: TObjectSettings,
|
||||
computedSettings: $TODO,
|
||||
object: TObject,
|
||||
onChangeSettings: $TODO,
|
||||
settingsModel: TSettingsModel,
|
||||
extra: TExtra = {},
|
||||
) {
|
||||
return Object.keys(settingDefs)
|
||||
.map(settingId =>
|
||||
@@ -189,6 +224,7 @@ export function getSettingsWidgets(
|
||||
computedSettings,
|
||||
object,
|
||||
onChangeSettings,
|
||||
settingsModel,
|
||||
extra,
|
||||
),
|
||||
)
|
||||
@@ -8,10 +8,7 @@ import {
|
||||
import { ChartSettingOrderedSimple } from "metabase/visualizations/components/settings/ChartSettingOrderedSimple";
|
||||
import { dimensionIsNumeric } from "metabase/visualizations/lib/numeric";
|
||||
import { columnSettings } from "metabase/visualizations/lib/settings/column";
|
||||
import {
|
||||
seriesSetting,
|
||||
keyForSingleSeries,
|
||||
} from "metabase/visualizations/lib/settings/series";
|
||||
import { seriesSetting } from "metabase/visualizations/lib/settings/series";
|
||||
import { getOptionFromColumn } from "metabase/visualizations/lib/settings/utils";
|
||||
import { dimensionIsTimeseries } from "metabase/visualizations/lib/timeseries";
|
||||
import { columnsAreValid, MAX_SERIES } from "metabase/visualizations/lib/utils";
|
||||
@@ -47,8 +44,8 @@ import {
|
||||
} from "metabase/visualizations/shared/settings/cartesian-chart";
|
||||
import { isNumeric } from "metabase-lib/v1/types/utils/isa";
|
||||
|
||||
export const getSeriesDisplays = (transformedSeries, settings) => {
|
||||
return transformedSeries.map(single => settings.series(single).display);
|
||||
export const getSeriesDisplays = (seriesModels, settings) => {
|
||||
return seriesModels.map(seriesModel => settings.series(seriesModel).display);
|
||||
};
|
||||
|
||||
export function getDefaultDimensionLabel(multipleSeries) {
|
||||
@@ -73,19 +70,17 @@ export const GRAPH_DATA_SETTINGS = {
|
||||
}),
|
||||
"graph._dimension_filter": {
|
||||
getDefault: ([{ card }]) => getDefaultDimensionFilter(card.display),
|
||||
useRawSeries: true,
|
||||
},
|
||||
"graph._metric_filter": {
|
||||
getDefault: ([{ card }]) => getDefaultMetricFilter(card.display),
|
||||
useRawSeries: true,
|
||||
},
|
||||
"graph.dimensions": {
|
||||
section: t`Data`,
|
||||
title: t`X-axis`,
|
||||
widget: "fields",
|
||||
getMarginBottom: (series, vizSettings) =>
|
||||
getMarginBottom: (_series, vizSettings, settingsModel) =>
|
||||
vizSettings["graph.dimensions"]?.length === 2 &&
|
||||
series.length <= MAX_SERIES
|
||||
settingsModel.seriesModels.length <= MAX_SERIES
|
||||
? "0.5rem"
|
||||
: "1rem",
|
||||
isValid: (series, vizSettings) =>
|
||||
@@ -120,7 +115,6 @@ export const GRAPH_DATA_SETTINGS = {
|
||||
writeDependencies: ["graph.metrics"],
|
||||
eraseDependencies: ["graph.series_order_dimension", "graph.series_order"],
|
||||
dashboard: false,
|
||||
useRawSeries: true,
|
||||
},
|
||||
"graph.series_order_dimension": {
|
||||
getValue: (_series, settings) => settings["graph.dimensions"][1],
|
||||
@@ -132,14 +126,14 @@ export const GRAPH_DATA_SETTINGS = {
|
||||
section: t`Data`,
|
||||
widget: ChartSettingOrderedSimple,
|
||||
marginBottom: "1rem",
|
||||
|
||||
getValue: (series, settings) => {
|
||||
const seriesKeys = series.map(s => keyForSingleSeries(s));
|
||||
getValue: (series, settings, settingsModel) => {
|
||||
const seriesKeys = settingsModel.seriesModels.map(s => s.vizSettingsKey);
|
||||
return getSeriesOrderVisibilitySettings(settings, seriesKeys);
|
||||
},
|
||||
getHidden: (series, settings) => {
|
||||
getHidden: (series, settings, settingsModel) => {
|
||||
return (
|
||||
settings["graph.dimensions"]?.length < 2 || series.length > MAX_SERIES
|
||||
settings["graph.dimensions"]?.length < 2 ||
|
||||
settingsModel.seriesModels.length > MAX_SERIES
|
||||
);
|
||||
},
|
||||
dashboard: false,
|
||||
@@ -178,7 +172,7 @@ export const GRAPH_DATA_SETTINGS = {
|
||||
showColumnSetting: true,
|
||||
showColorPicker: !hasBreakout,
|
||||
colors: vizSettings["series_settings.colors"],
|
||||
series: extra.transformedSeries,
|
||||
series: extra.transformedSeries, // put here series models
|
||||
};
|
||||
},
|
||||
readDependencies: [
|
||||
@@ -188,7 +182,7 @@ export const GRAPH_DATA_SETTINGS = {
|
||||
],
|
||||
writeDependencies: ["graph.dimensions"],
|
||||
dashboard: false,
|
||||
useRawSeries: true,
|
||||
// useRawSeries: true,
|
||||
},
|
||||
...seriesSetting(),
|
||||
};
|
||||
@@ -216,7 +210,6 @@ export const GRAPH_BUBBLE_SETTINGS = {
|
||||
},
|
||||
writeDependencies: ["graph.dimensions"],
|
||||
dashboard: false,
|
||||
useRawSeries: true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -245,8 +238,11 @@ export const STACKABLE_SETTINGS = {
|
||||
{ name: t`Stack - 100%`, value: "normalized" },
|
||||
],
|
||||
},
|
||||
isValid: (series, settings) => {
|
||||
const seriesDisplays = getSeriesDisplays(series, settings);
|
||||
isValid: (series, settings, settingsModel) => {
|
||||
const seriesDisplays = getSeriesDisplays(
|
||||
settingsModel.seriesModels,
|
||||
settings,
|
||||
);
|
||||
|
||||
return isStackingValueValid(
|
||||
series[0].card.display,
|
||||
@@ -297,7 +293,6 @@ export const GRAPH_TREND_SETTINGS = {
|
||||
const { insights } = series[0].data;
|
||||
return !insights || insights.length === 0;
|
||||
},
|
||||
useRawSeries: true,
|
||||
inline: true,
|
||||
marginBottom: "1rem",
|
||||
},
|
||||
@@ -308,7 +303,8 @@ export const GRAPH_DISPLAY_VALUES_SETTINGS = {
|
||||
section: t`Display`,
|
||||
title: t`Show values on data points`,
|
||||
widget: "toggle",
|
||||
getHidden: (series, vizSettings) => !canHaveDataLabels(series, vizSettings),
|
||||
getHidden: (series, vizSettings, settingsModel) =>
|
||||
!canHaveDataLabels(settingsModel.seriesModels, vizSettings),
|
||||
getDefault: getDefaultShowDataLabels,
|
||||
inline: true,
|
||||
marginBottom: "1rem",
|
||||
@@ -317,26 +313,28 @@ export const GRAPH_DISPLAY_VALUES_SETTINGS = {
|
||||
section: t`Display`,
|
||||
title: t`Values to show`,
|
||||
widget: "segmentedControl",
|
||||
getHidden: (series, vizSettings) => {
|
||||
getHidden: (series, vizSettings, settingsModel) => {
|
||||
if (!vizSettings["graph.show_values"]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const areAllBars = getSeriesDisplays(series, vizSettings).every(
|
||||
display => display === "bar",
|
||||
);
|
||||
const areAllBars = getSeriesDisplays(
|
||||
settingsModel.seriesModels,
|
||||
vizSettings,
|
||||
).every(display => display === "bar");
|
||||
if (areAllBars && vizSettings["graph.show_stack_values"] === "series") {
|
||||
return true;
|
||||
}
|
||||
|
||||
const hasLines = getSeriesDisplays(series, vizSettings).some(
|
||||
display => display === "line",
|
||||
);
|
||||
const hasLines = getSeriesDisplays(
|
||||
settingsModel.seriesModels,
|
||||
vizSettings,
|
||||
).some(display => display === "line");
|
||||
if (vizSettings["stackable.stack_type"] === "normalized" && !hasLines) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !canHaveDataLabels(series, vizSettings);
|
||||
return !canHaveDataLabels(settingsModel.seriesModels, vizSettings);
|
||||
},
|
||||
props: {
|
||||
options: [
|
||||
@@ -351,19 +349,20 @@ export const GRAPH_DISPLAY_VALUES_SETTINGS = {
|
||||
section: t`Display`,
|
||||
title: t`Stack values to show`,
|
||||
widget: "segmentedControl",
|
||||
getHidden: (series, vizSettings) => {
|
||||
const hasBars = getSeriesDisplays(series, vizSettings).some(
|
||||
display => display === "bar",
|
||||
);
|
||||
getHidden: (series, vizSettings, settingsModel) => {
|
||||
const hasBars = getSeriesDisplays(
|
||||
settingsModel.seriesModels,
|
||||
vizSettings,
|
||||
).some(display => display === "bar");
|
||||
return (
|
||||
vizSettings["stackable.stack_type"] !== "stacked" ||
|
||||
vizSettings["graph.show_values"] !== true ||
|
||||
!hasBars
|
||||
);
|
||||
},
|
||||
isValid: (series, vizSettings) => {
|
||||
isValid: (series, vizSettings, settingsModel) => {
|
||||
return isShowStackValuesValid(
|
||||
getSeriesDisplays(series, vizSettings),
|
||||
getSeriesDisplays(settingsModel.seriesModels, vizSettings),
|
||||
vizSettings,
|
||||
);
|
||||
},
|
||||
@@ -504,12 +503,18 @@ export const GRAPH_AXIS_SETTINGS = {
|
||||
widget: "toggle",
|
||||
index: 5,
|
||||
inline: true,
|
||||
isValid: (series, settings) => {
|
||||
const seriesDisplays = getSeriesDisplays(series, settings);
|
||||
isValid: (series, settings, settingsModel) => {
|
||||
const seriesDisplays = getSeriesDisplays(
|
||||
settingsModel.seriesModels,
|
||||
settings,
|
||||
);
|
||||
return isYAxisUnpinFromZeroValid(seriesDisplays, settings);
|
||||
},
|
||||
getHidden: (series, settings) => {
|
||||
const seriesDisplays = getSeriesDisplays(series, settings);
|
||||
getHidden: (series, settings, settingsModel) => {
|
||||
const seriesDisplays = getSeriesDisplays(
|
||||
settingsModel.seriesModels,
|
||||
settings,
|
||||
);
|
||||
return !isYAxisUnpinFromZeroValid(seriesDisplays, settings);
|
||||
},
|
||||
getDefault: series => {
|
||||
@@ -554,7 +559,8 @@ export const GRAPH_AXIS_SETTINGS = {
|
||||
widget: "toggle",
|
||||
inline: true,
|
||||
getDefault: getDefaultIsAutoSplitEnabled,
|
||||
getHidden: series => series.length < 2,
|
||||
getHidden: (series, settings, settingsModel) =>
|
||||
settingsModel.seriesModels.length < 2,
|
||||
},
|
||||
"graph.x_axis.labels_enabled": {
|
||||
section: t`Axes`,
|
||||
|
||||
@@ -1,12 +1,38 @@
|
||||
import type React from "react";
|
||||
import { t } from "ttag";
|
||||
import _ from "underscore";
|
||||
|
||||
import chartSettingNestedSettings from "metabase/visualizations/components/settings/ChartSettingNestedSettings";
|
||||
import type { ComputedVisualizationSettings } from "metabase/visualizations/types";
|
||||
import type { RawSeries } from "metabase-types/api";
|
||||
|
||||
import { getComputedSettings, getSettingsWidgets } from "../settings";
|
||||
|
||||
export function nestedSettings(
|
||||
id,
|
||||
import { getSettingsModelForSeries } from "./visualization";
|
||||
|
||||
type NestedSettingsDefinition<TObject> = {
|
||||
objectName: string;
|
||||
getObjects: (
|
||||
series: RawSeries,
|
||||
settings: ComputedVisualizationSettings,
|
||||
) => TObject[];
|
||||
getObjectKey: (object: TObject) => string;
|
||||
getSettingDefinitionsForObject: (
|
||||
rawSeries: RawSeries,
|
||||
object: TObject,
|
||||
) => $TODO;
|
||||
getInheritedSettingsForObject: (object: TObject) => $TODO;
|
||||
component: React.ReactNode;
|
||||
getExtraProps: () => $TODO;
|
||||
};
|
||||
|
||||
export function nestedSettings<
|
||||
TObject,
|
||||
TObjectSettings extends Record<string, unknown>,
|
||||
TExtra,
|
||||
TSettingsModel,
|
||||
>(
|
||||
id: string,
|
||||
{
|
||||
objectName = "object",
|
||||
getObjects,
|
||||
@@ -15,34 +41,43 @@ export function nestedSettings(
|
||||
getInheritedSettingsForObject = () => ({}),
|
||||
component,
|
||||
...def
|
||||
} = {},
|
||||
}: NestedSettingsDefinition<TObject>,
|
||||
) {
|
||||
function getComputedSettingsForObject(series, object, storedSettings, extra) {
|
||||
function getComputedSettingsForObject(
|
||||
series: RawSeries,
|
||||
object: TObject,
|
||||
storedSettings: TObjectSettings,
|
||||
settingsModel: TSettingsModel,
|
||||
extra: TExtra,
|
||||
): Partial<TObjectSettings> {
|
||||
const settingsDefs = getSettingDefinitionsForObject(series, object);
|
||||
const inheritedSettings = getInheritedSettingsForObject(object);
|
||||
const computedSettings = getComputedSettings(
|
||||
settingsDefs,
|
||||
object,
|
||||
{ ...inheritedSettings, ...storedSettings },
|
||||
settingsModel,
|
||||
extra,
|
||||
);
|
||||
) as TObjectSettings;
|
||||
// remove undefined settings since they override other settings when merging object
|
||||
return _.pick(computedSettings, value => value !== undefined);
|
||||
}
|
||||
|
||||
function getComputedSettingsForAllObjects(
|
||||
series,
|
||||
objects,
|
||||
allStoredSettings,
|
||||
extra,
|
||||
series: RawSeries,
|
||||
objects: TObject[],
|
||||
allStoredSettings: Record<string, TObjectSettings>,
|
||||
settingsModel: unknown,
|
||||
extra: TExtra,
|
||||
) {
|
||||
const allComputedSettings = {};
|
||||
const allComputedSettings: Record<string, Partial<TObjectSettings>> = {};
|
||||
for (const object of objects) {
|
||||
const key = getObjectKey(object);
|
||||
allComputedSettings[key] = getComputedSettingsForObject(
|
||||
series,
|
||||
object,
|
||||
allStoredSettings[key] || {},
|
||||
settingsModel,
|
||||
extra,
|
||||
);
|
||||
}
|
||||
@@ -50,17 +85,19 @@ export function nestedSettings(
|
||||
}
|
||||
|
||||
function getSettingsWidgetsForObject(
|
||||
series,
|
||||
object,
|
||||
storedSettings,
|
||||
onChangeSettings,
|
||||
extra,
|
||||
series: RawSeries,
|
||||
object: TObject,
|
||||
storedSettings: TObjectSettings,
|
||||
onChangeSettings: (settings: TObjectSettings) => void,
|
||||
settingsModel,
|
||||
extra: TExtra,
|
||||
) {
|
||||
const settingsDefs = getSettingDefinitionsForObject(series, object);
|
||||
const computedSettings = getComputedSettingsForObject(
|
||||
series,
|
||||
object,
|
||||
storedSettings,
|
||||
settingsModel,
|
||||
extra,
|
||||
);
|
||||
const widgets = getSettingsWidgets(
|
||||
@@ -69,6 +106,7 @@ export function nestedSettings(
|
||||
computedSettings,
|
||||
object,
|
||||
onChangeSettings,
|
||||
settingsModel,
|
||||
extra,
|
||||
);
|
||||
return widgets.map(widget => ({ ...widget, noPadding: true }));
|
||||
@@ -84,12 +122,19 @@ export function nestedSettings(
|
||||
[id]: {
|
||||
section: t`Display`,
|
||||
default: {},
|
||||
getProps: (series, settings, onChange, extra) => {
|
||||
const objects = getObjects(series, settings);
|
||||
getProps: (
|
||||
series: RawSeries,
|
||||
settings: ComputedVisualizationSettings,
|
||||
onChange,
|
||||
settingsModel,
|
||||
extra: TExtra,
|
||||
) => {
|
||||
const objects = getObjects(series, settings, settingsModel);
|
||||
const allComputedSettings = getComputedSettingsForAllObjects(
|
||||
series,
|
||||
objects,
|
||||
settings[id],
|
||||
settingsModel,
|
||||
{ series, settings },
|
||||
);
|
||||
return {
|
||||
@@ -106,10 +151,15 @@ export function nestedSettings(
|
||||
...def,
|
||||
},
|
||||
[objectName]: {
|
||||
getDefault(series, settings) {
|
||||
getDefault(
|
||||
series: RawSeries,
|
||||
settings: ComputedVisualizationSettings,
|
||||
settingsModel: TSettingsModel,
|
||||
) {
|
||||
const cache = new Map();
|
||||
return object => {
|
||||
return (object: TObject) => {
|
||||
const key = getObjectKey(object);
|
||||
|
||||
if (!cache.has(key)) {
|
||||
const inheritedSettings = getInheritedSettingsForObject(object);
|
||||
const storedSettings = settings[id][key] || {};
|
||||
@@ -121,6 +171,7 @@ export function nestedSettings(
|
||||
...inheritedSettings,
|
||||
...storedSettings,
|
||||
},
|
||||
settingsModel,
|
||||
{ series, settings },
|
||||
),
|
||||
});
|
||||
@@ -1,8 +1,10 @@
|
||||
import { getIn } from "icepick";
|
||||
import type React from "react";
|
||||
import { t } from "ttag";
|
||||
import _ from "underscore";
|
||||
|
||||
import ChartNestedSettingSeries from "metabase/visualizations/components/settings/ChartNestedSettingSeries";
|
||||
import type { SeriesModel } from "metabase/visualizations/echarts/cartesian/model/types";
|
||||
import {
|
||||
SERIES_COLORS_SETTING_KEY,
|
||||
getSeriesDefaultLinearInterpolate,
|
||||
@@ -15,35 +17,61 @@ import {
|
||||
getSeriesDefaultLineStyle,
|
||||
getSeriesDefaultLineSize,
|
||||
} from "metabase/visualizations/shared/settings/series";
|
||||
|
||||
import { getNameForCard } from "../series";
|
||||
import type { RawSeries, SeriesSettings } from "metabase-types/api";
|
||||
|
||||
import { nestedSettings } from "./nested";
|
||||
|
||||
export function keyForSingleSeries(single) {
|
||||
// _seriesKey is sometimes set by transformSeries
|
||||
return single.card._seriesKey || String(single.card.name);
|
||||
}
|
||||
|
||||
const LINE_DISPLAY_TYPES = new Set(["line", "area"]);
|
||||
|
||||
type ComputedSeriesSettings = NonNullableProps<
|
||||
SeriesSettings,
|
||||
"title" | "display"
|
||||
>;
|
||||
|
||||
type NestedSettingsDefinition<
|
||||
TObject,
|
||||
TObjectSettings,
|
||||
TValue,
|
||||
TSettingsModel,
|
||||
TWidgetProps,
|
||||
TExtra,
|
||||
> = {
|
||||
widget?: string | React.ReactNode;
|
||||
title?: string;
|
||||
props?: TWidgetProps;
|
||||
getDefault?: (
|
||||
object: TObject,
|
||||
settings: TObjectSettings,
|
||||
settingsModel: TSettingsModel,
|
||||
extra: TExtra,
|
||||
) => TValue;
|
||||
getHidden?: (
|
||||
object: TObject,
|
||||
settings: TObjectSettings,
|
||||
settingsModel: TSettingsModel,
|
||||
extra: TExtra,
|
||||
) => TValue;
|
||||
readDependencies?: string[];
|
||||
};
|
||||
|
||||
type NestedSettingsDefinitions = Record<
|
||||
string,
|
||||
NestedSettingsDefinition<SeriesModel, SeriesSettings, unknown, unknown>
|
||||
>;
|
||||
|
||||
export function seriesSetting({
|
||||
readDependencies = [],
|
||||
noPadding,
|
||||
...def
|
||||
} = {}) {
|
||||
const COMMON_SETTINGS = {
|
||||
} = {}): Record<
|
||||
string,
|
||||
NestedSettingsDefinition<SeriesModel, SeriesSettings, unknown, unknown>
|
||||
> {
|
||||
const COMMON_SETTINGS: NestedSettingsDefinitions = {
|
||||
// title, and color don't need widgets because they're handled directly in ChartNestedSettingSeries
|
||||
title: {
|
||||
getDefault: (single, settings, { series, settings: vizSettings }) => {
|
||||
const legacyTitles = vizSettings["graph.series_labels"];
|
||||
if (legacyTitles) {
|
||||
const index = series.indexOf(single); // TODO: pass in series index so we don't have to search for it
|
||||
if (index >= 0 && index < legacyTitles.length) {
|
||||
return legacyTitles[index];
|
||||
}
|
||||
}
|
||||
return single.card.name;
|
||||
getDefault: (single, settings, settingsModel) => {
|
||||
return single.name;
|
||||
},
|
||||
},
|
||||
display: {
|
||||
@@ -56,32 +84,25 @@ export function seriesSetting({
|
||||
{ value: "bar", icon: "bar" },
|
||||
],
|
||||
},
|
||||
getHidden: (single, settings, { series }) => {
|
||||
getHidden: (single, settings, settingsModel) => {
|
||||
return (
|
||||
!["line", "area", "bar", "combo"].includes(single.card.display) ||
|
||||
!["line", "area", "bar", "combo"].includes(settingsModel.display) ||
|
||||
settings["stackable.stack_type"] != null
|
||||
);
|
||||
},
|
||||
|
||||
getDefault: (single, settings, { series }) => {
|
||||
// FIXME: will move to Cartesian series model further, but now this code is used by other legacy charts
|
||||
const transformedSeriesIndex = series.findIndex(
|
||||
s => keyForSingleSeries(s) === keyForSingleSeries(single),
|
||||
getDefault: (single, settings, settingsModel) => {
|
||||
const index = settingsModel.seriesModels.find(
|
||||
sm => sm.vizSettingsKey === single.vizSettingsKey,
|
||||
);
|
||||
|
||||
return getSeriesDefaultDisplay(
|
||||
series[transformedSeriesIndex].card.display,
|
||||
transformedSeriesIndex,
|
||||
);
|
||||
return getSeriesDefaultDisplay(settingsModel.display, index);
|
||||
},
|
||||
},
|
||||
color: {
|
||||
getDefault: (single, settings, { settings: vizSettings }) =>
|
||||
// get the color for series key, computed in the setting
|
||||
getIn(vizSettings, [
|
||||
SERIES_COLORS_SETTING_KEY,
|
||||
keyForSingleSeries(single),
|
||||
]),
|
||||
getIn(vizSettings, [SERIES_COLORS_SETTING_KEY, single.vizSettingsKey]),
|
||||
},
|
||||
"line.interpolate": {
|
||||
title: t`Line shape`,
|
||||
@@ -95,7 +116,12 @@ export function seriesSetting({
|
||||
},
|
||||
getHidden: (single, settings) =>
|
||||
!LINE_DISPLAY_TYPES.has(settings["display"]),
|
||||
getDefault: (single, settings, { settings: vizSettings }) =>
|
||||
getDefault: (
|
||||
single,
|
||||
settings,
|
||||
_settingsModel,
|
||||
{ settings: vizSettings },
|
||||
) =>
|
||||
// use legacy global line.interpolate setting if present
|
||||
getSeriesDefaultLinearInterpolate(vizSettings),
|
||||
readDependencies: ["display"],
|
||||
@@ -110,9 +136,10 @@ export function seriesSetting({
|
||||
{ icon: "line_style_dotted", value: "dotted" },
|
||||
],
|
||||
},
|
||||
getDefault: (series, settings) => getSeriesDefaultLineStyle(settings),
|
||||
getHidden: (single, settings) =>
|
||||
!LINE_DISPLAY_TYPES.has(settings["display"]),
|
||||
getDefault: (series: SeriesModel, settings: SeriesSettings) =>
|
||||
getSeriesDefaultLineStyle(settings),
|
||||
getHidden: (seriesModel: SeriesModel, settings: SeriesSettings) =>
|
||||
!LINE_DISPLAY_TYPES.has(settings.display),
|
||||
readDependencies: ["display"],
|
||||
},
|
||||
"line.size": {
|
||||
@@ -157,9 +184,14 @@ export function seriesSetting({
|
||||
{ name: t`Linear Interpolated`, value: "interpolate" },
|
||||
],
|
||||
},
|
||||
getHidden: (single, settings) =>
|
||||
getHidden: (seriesModel: SeriesModel, settings: SeriesSettings) =>
|
||||
!LINE_DISPLAY_TYPES.has(settings["display"]),
|
||||
getDefault: (single, settings, { settings: vizSettings }) =>
|
||||
getDefault: (
|
||||
single,
|
||||
settings,
|
||||
settingsModel,
|
||||
{ settings: vizSettings },
|
||||
) =>
|
||||
// use legacy global line.missing setting if present
|
||||
getSeriesDefaultLineMissing(vizSettings),
|
||||
readDependencies: ["display"],
|
||||
@@ -168,7 +200,8 @@ export function seriesSetting({
|
||||
title: t`Y-axis position`,
|
||||
widget: "segmentedControl",
|
||||
default: null,
|
||||
getHidden: (single, settings) => single.card.display === "row",
|
||||
getHidden: (single, settings, settingsModel) =>
|
||||
settingsModel.display === "row",
|
||||
props: {
|
||||
options: [
|
||||
{ name: t`Auto`, value: null },
|
||||
@@ -182,17 +215,22 @@ export function seriesSetting({
|
||||
title: t`Show values for this series`,
|
||||
widget: "toggle",
|
||||
inline: true,
|
||||
getHidden: (single, seriesSettings, { settings, series }) =>
|
||||
getHidden: (
|
||||
single,
|
||||
seriesSettings,
|
||||
settingsModel,
|
||||
{ settings, series },
|
||||
) =>
|
||||
series.length <= 1 || // no need to show series-level control if there's only one series
|
||||
!settings["graph.show_values"] || // don't show it unless this chart has a global setting
|
||||
settings["stackable.stack_type"], // hide series controls if the chart is stacked
|
||||
getDefault: (single, seriesSettings, { settings }) =>
|
||||
getDefault: (single, seriesSettings, settingsModel, { settings }) =>
|
||||
getSeriesDefaultShowSeriesValues(settings),
|
||||
readDependencies: ["graph.show_values", "stackable.stack_type"],
|
||||
},
|
||||
};
|
||||
|
||||
function getSettingDefinitionsForSingleSeries(series, object, settings) {
|
||||
function getSettingDefinitionsForSingleSeries() {
|
||||
return COMMON_SETTINGS;
|
||||
}
|
||||
|
||||
@@ -203,26 +241,21 @@ export function seriesSetting({
|
||||
getSection: (series, settings, { isDashboard }) =>
|
||||
isDashboard ? t`Display` : t`Style`,
|
||||
objectName: "series",
|
||||
getObjects: (series, settings) => series,
|
||||
getObjectKey: keyForSingleSeries,
|
||||
getObjects: (series, settings, settingsModel) => {
|
||||
return settingsModel.seriesModels;
|
||||
},
|
||||
getObjectKey: seriesModel => seriesModel.vizSettingsKey,
|
||||
getSettingDefinitionsForObject: getSettingDefinitionsForSingleSeries,
|
||||
component: ChartNestedSettingSeries,
|
||||
readDependencies: [SERIES_COLORS_SETTING_KEY, ...readDependencies],
|
||||
noPadding: true,
|
||||
getExtraProps: series => ({
|
||||
seriesCardNames: series.reduce((memo, singleSeries) => {
|
||||
memo[keyForSingleSeries(singleSeries)] = getNameForCard(
|
||||
singleSeries.card,
|
||||
);
|
||||
return memo;
|
||||
}, {}),
|
||||
}),
|
||||
...def,
|
||||
}),
|
||||
// colors must be computed as a whole rather than individually
|
||||
[SERIES_COLORS_SETTING_KEY]: {
|
||||
getValue(series, settings) {
|
||||
const keys = series.map(single => keyForSingleSeries(single));
|
||||
getValue(series, settings, settingsModel) {
|
||||
// const keys = series.map(single => keyForSingleSeries(single));
|
||||
const keys = settingsModel.seriesModels.map(s => s.vizSettingsKey);
|
||||
return getSeriesColors(keys, settings);
|
||||
},
|
||||
},
|
||||
@@ -45,6 +45,14 @@ const COMMON_SETTINGS = {
|
||||
click_behavior: {},
|
||||
};
|
||||
|
||||
export function getSettingsModelForSeries(series, settings) {
|
||||
if (!series) {
|
||||
return null;
|
||||
}
|
||||
const visualization = getVisualizationRaw(series);
|
||||
return visualization.getSettingsModel?.(series, settings);
|
||||
}
|
||||
|
||||
function getSettingDefintionsForSeries(series) {
|
||||
if (!series) {
|
||||
return {};
|
||||
@@ -94,7 +102,14 @@ export function getComputedSettingsForSeries(series) {
|
||||
}
|
||||
const settingsDefs = getSettingDefintionsForSeries(series);
|
||||
const storedSettings = getStoredSettingsForSeries(series);
|
||||
return getComputedSettings(settingsDefs, series, storedSettings);
|
||||
const settingsModel = getSettingsModelForSeries(series, storedSettings);
|
||||
return getComputedSettings(
|
||||
settingsDefs,
|
||||
series,
|
||||
storedSettings,
|
||||
settingsModel,
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
export function getPersistableDefaultSettingsForSeries(series) {
|
||||
@@ -109,6 +124,7 @@ export function getSettingsWidgetsForSeries(
|
||||
series,
|
||||
onChangeSettings,
|
||||
isDashboard = false,
|
||||
settingsModel,
|
||||
extra = {},
|
||||
) {
|
||||
const settingsDefs = getSettingDefintionsForSeries(series);
|
||||
@@ -121,6 +137,7 @@ export function getSettingsWidgetsForSeries(
|
||||
computedSettings,
|
||||
series,
|
||||
onChangeSettings,
|
||||
settingsModel,
|
||||
{ isDashboard, ...extra },
|
||||
).filter(
|
||||
widget =>
|
||||
|
||||
@@ -11,10 +11,8 @@ import type {
|
||||
DatasetColumn,
|
||||
DatasetData,
|
||||
RawSeries,
|
||||
Series,
|
||||
TimelineEvent,
|
||||
TimelineEventId,
|
||||
TransformedSeries,
|
||||
VisualizationSettings,
|
||||
} from "metabase-types/api";
|
||||
|
||||
@@ -71,7 +69,7 @@ export interface StaticVisualizationProps {
|
||||
}
|
||||
|
||||
export interface VisualizationProps {
|
||||
series: Series;
|
||||
series: RawSeries;
|
||||
card: Card;
|
||||
href: string | undefined;
|
||||
data: DatasetData;
|
||||
@@ -141,41 +139,85 @@ export type ColumnSettingDefinition<TValue, TProps = unknown> = {
|
||||
col: DatasetColumn,
|
||||
settings: OptionsType,
|
||||
onChange: (value: TValue) => void,
|
||||
extra: { series: Series },
|
||||
extra: { series: RawSeries },
|
||||
) => TProps;
|
||||
};
|
||||
|
||||
export type VisualizationSettingDefinition<TValue, TProps = void> = {
|
||||
export type VisualizationSettingDefinition<
|
||||
TObject,
|
||||
TObjectSettings,
|
||||
TValue,
|
||||
TSettingsModel,
|
||||
TWidgetProps,
|
||||
TExtra,
|
||||
> = {
|
||||
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;
|
||||
getValue?: (series: Series, settings: VisualizationSettings) => TValue;
|
||||
widget?: string | React.ComponentType<TWidgetProps>;
|
||||
isValid?: (
|
||||
series: TObject,
|
||||
settings: TObjectSettings,
|
||||
settingsModel: TSettingsModel,
|
||||
extra: TExtra,
|
||||
) => boolean;
|
||||
getHidden?: (
|
||||
series: TObject,
|
||||
settings: TObjectSettings,
|
||||
settingsModel: TSettingsModel,
|
||||
extra: TExtra,
|
||||
) => boolean;
|
||||
getDefault?: (
|
||||
series: TObject,
|
||||
settings: TObjectSettings,
|
||||
settingsModel: TSettingsModel,
|
||||
extra: TExtra,
|
||||
) => TValue;
|
||||
getValue?: (
|
||||
series: TObject,
|
||||
settings: TObjectSettings,
|
||||
settingsModel: TSettingsModel,
|
||||
extra: TExtra,
|
||||
) => TValue;
|
||||
default?: TValue;
|
||||
marginBottom?: string;
|
||||
getMarginBottom?: (series: Series, settings: VisualizationSettings) => string;
|
||||
getMarginBottom?: (
|
||||
series: TObject,
|
||||
settings: TObjectSettings,
|
||||
settingsModel: TSettingsModel,
|
||||
extra: TExtra,
|
||||
) => string;
|
||||
persistDefault?: boolean;
|
||||
inline?: boolean;
|
||||
props?: TProps;
|
||||
props?: TWidgetProps;
|
||||
getProps?: (
|
||||
series: Series,
|
||||
vizSettings: VisualizationSettings,
|
||||
series: TObject,
|
||||
vizSettings: TObjectSettings,
|
||||
onChange: (value: TValue) => void,
|
||||
extra: unknown,
|
||||
) => TProps;
|
||||
) => TWidgetProps;
|
||||
readDependencies?: string[];
|
||||
writeDependencies?: string[];
|
||||
eraseDependencies?: string[];
|
||||
// is the setting visible in the dashboard card viz settings
|
||||
dashboard?: boolean;
|
||||
useRawSeries?: boolean;
|
||||
dashboard?: boolean; // is the setting visible in the dashboard card viz settings
|
||||
};
|
||||
|
||||
export type VisualizationSettingsDefinitions = {
|
||||
[key: string]: VisualizationSettingDefinition<unknown, unknown>;
|
||||
export type VisualizationSettingsDefinitions<
|
||||
TObject,
|
||||
TObjectSettings,
|
||||
TValue,
|
||||
TSettingsModel,
|
||||
TWidgetProps,
|
||||
TExtra,
|
||||
> = {
|
||||
[key: string]: VisualizationSettingDefinition<
|
||||
TObject,
|
||||
TObjectSettings,
|
||||
TValue,
|
||||
TSettingsModel,
|
||||
TWidgetProps,
|
||||
TExtra
|
||||
>;
|
||||
};
|
||||
|
||||
export type VisualizationGridSize = {
|
||||
@@ -186,42 +228,56 @@ export type VisualizationGridSize = {
|
||||
};
|
||||
|
||||
// TODO: add component property for the react component instead of the intersection
|
||||
export type Visualization = React.ComponentType<VisualizationProps> & {
|
||||
name: string;
|
||||
noun: string;
|
||||
uiName: string;
|
||||
identifier: string;
|
||||
aliases?: string[];
|
||||
iconName: IconName;
|
||||
export type Visualization<TSettingsModel = unknown> =
|
||||
React.ComponentType<VisualizationProps> & {
|
||||
name: string;
|
||||
noun: string;
|
||||
uiName: string;
|
||||
identifier: string;
|
||||
aliases?: string[];
|
||||
iconName: IconName;
|
||||
|
||||
maxMetricsSupported: number;
|
||||
maxDimensionsSupported: number;
|
||||
maxMetricsSupported: number;
|
||||
maxDimensionsSupported: number;
|
||||
|
||||
disableClickBehavior?: boolean;
|
||||
canSavePng?: boolean;
|
||||
noHeader: boolean;
|
||||
hidden?: boolean;
|
||||
disableSettingsConfig?: boolean;
|
||||
supportPreviewing?: boolean;
|
||||
supportsSeries?: boolean;
|
||||
disableClickBehavior?: boolean;
|
||||
canSavePng?: boolean;
|
||||
noHeader: boolean;
|
||||
hidden?: boolean;
|
||||
disableSettingsConfig?: boolean;
|
||||
supportPreviewing?: boolean;
|
||||
supportsSeries?: boolean;
|
||||
|
||||
minSize: VisualizationGridSize;
|
||||
defaultSize: VisualizationGridSize;
|
||||
minSize: VisualizationGridSize;
|
||||
defaultSize: VisualizationGridSize;
|
||||
|
||||
settings: VisualizationSettingsDefinitions;
|
||||
settings: VisualizationSettingsDefinitions<
|
||||
RawSeries,
|
||||
VisualizationSettings,
|
||||
unknown,
|
||||
TSettingsModel,
|
||||
unknown,
|
||||
unknown
|
||||
>;
|
||||
|
||||
placeHolderSeries: Series;
|
||||
placeHolderSeries: RawSeries;
|
||||
|
||||
transformSeries: (series: Series) => TransformedSeries;
|
||||
// TODO: remove dependency on metabase-lib
|
||||
isSensible: (data: DatasetData, query?: Query) => boolean;
|
||||
// checkRenderable throws an error if a visualization is not renderable
|
||||
checkRenderable: (
|
||||
series: Series,
|
||||
settings: VisualizationSettings,
|
||||
query: Query,
|
||||
) => void | never;
|
||||
isLiveResizable: (series: Series) => boolean;
|
||||
onDisplayUpdate?: (settings: VisualizationSettings) => VisualizationSettings;
|
||||
placeholderSeries: RawSeries;
|
||||
};
|
||||
getSettingsModel?: (
|
||||
rawSeries: RawSeries,
|
||||
settings: VisualizationSettings,
|
||||
) => TSettingsModel;
|
||||
|
||||
// TODO: remove dependency on metabase-lib
|
||||
isSensible: (data: DatasetData, query?: Query) => boolean;
|
||||
// checkRenderable throws an error if a visualization is not renderable
|
||||
checkRenderable: (
|
||||
series: RawSeries,
|
||||
settings: VisualizationSettings,
|
||||
query: Query,
|
||||
) => void | never;
|
||||
isLiveResizable: (series: RawSeries) => boolean;
|
||||
onDisplayUpdate?: (
|
||||
settings: VisualizationSettings,
|
||||
) => VisualizationSettings;
|
||||
placeholderSeries: RawSeries;
|
||||
};
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
import _ from "underscore";
|
||||
|
||||
import { NULL_DISPLAY_VALUE } from "metabase/lib/constants";
|
||||
import { formatValue } from "metabase/lib/formatting";
|
||||
import { isEmpty } from "metabase/lib/validate";
|
||||
import { getComputedSettingsForSeries } from "metabase/visualizations/lib/settings/visualization";
|
||||
import { getFriendlyName } from "metabase/visualizations/lib/utils";
|
||||
|
||||
// TODO: this series transformation is used only for the visualization settings computation which is excessive.
|
||||
// Replace this with defining settings models per visualization type which will contain all necessary info
|
||||
// about the dataset sufficient to compute settings defaults like series settings.
|
||||
export function transformSeries(series) {
|
||||
const newSeries = [].concat(
|
||||
...series.map((s, seriesIndex) =>
|
||||
transformSingleSeries(s, series, seriesIndex),
|
||||
),
|
||||
);
|
||||
if (_.isEqual(series, newSeries) || newSeries.length === 0) {
|
||||
return series;
|
||||
} else {
|
||||
return newSeries;
|
||||
}
|
||||
}
|
||||
|
||||
function transformSingleSeries(s, series, seriesIndex) {
|
||||
const { card, data } = s;
|
||||
|
||||
// HACK: prevents cards from being transformed too many times
|
||||
if (data._transformed) {
|
||||
return [s];
|
||||
}
|
||||
|
||||
const { cols, rows } = data;
|
||||
const settings = getComputedSettingsForSeries([s]);
|
||||
|
||||
const dimensions = (settings["graph.dimensions"] || []).filter(
|
||||
d => d != null,
|
||||
);
|
||||
const metrics = (settings["graph.metrics"] || []).filter(d => d != null);
|
||||
const dimensionColumnIndexes = dimensions.map(dimensionName =>
|
||||
_.findIndex(cols, col => col.name === dimensionName),
|
||||
);
|
||||
const metricColumnIndexes = metrics.map(metricName =>
|
||||
_.findIndex(cols, col => col.name === metricName),
|
||||
);
|
||||
const bubbleColumnIndex =
|
||||
settings["scatter.bubble"] &&
|
||||
_.findIndex(cols, col => col.name === settings["scatter.bubble"]);
|
||||
const extraColumnIndexes =
|
||||
bubbleColumnIndex != null && bubbleColumnIndex >= 0
|
||||
? [bubbleColumnIndex]
|
||||
: [];
|
||||
|
||||
if (dimensions.length > 1) {
|
||||
const [dimensionColumnIndex, seriesColumnIndex] = dimensionColumnIndexes;
|
||||
const rowColumnIndexes = [dimensionColumnIndex].concat(
|
||||
metricColumnIndexes,
|
||||
extraColumnIndexes,
|
||||
);
|
||||
|
||||
const breakoutValues = [];
|
||||
const breakoutRowsByValue = new Map();
|
||||
|
||||
for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
|
||||
const row = rows[rowIndex];
|
||||
const seriesValue = row[seriesColumnIndex];
|
||||
|
||||
let seriesRows = breakoutRowsByValue.get(seriesValue);
|
||||
if (!seriesRows) {
|
||||
breakoutRowsByValue.set(seriesValue, (seriesRows = []));
|
||||
breakoutValues.push(seriesValue);
|
||||
}
|
||||
|
||||
const newRow = rowColumnIndexes.map(columnIndex => row[columnIndex]);
|
||||
newRow._origin = { seriesIndex, rowIndex, row, cols };
|
||||
seriesRows.push(newRow);
|
||||
}
|
||||
|
||||
return breakoutValues.map(breakoutValue => ({
|
||||
card: {
|
||||
...card,
|
||||
// if multiseries include the card title as well as the breakout value
|
||||
name: [
|
||||
// show series title if it's multiseries
|
||||
series.length > 1 && card.name,
|
||||
// always show grouping value
|
||||
formatValue(
|
||||
isEmpty(breakoutValue) ? NULL_DISPLAY_VALUE : breakoutValue,
|
||||
{ column: cols[seriesColumnIndex] },
|
||||
),
|
||||
]
|
||||
.filter(n => n)
|
||||
.join(": "),
|
||||
originalCardName: card.name,
|
||||
_breakoutValue: breakoutValue,
|
||||
_breakoutColumn: cols[seriesColumnIndex],
|
||||
},
|
||||
data: {
|
||||
rows: breakoutRowsByValue.get(breakoutValue),
|
||||
cols: rowColumnIndexes.map(i => cols[i]),
|
||||
results_timezone: data.results_timezone,
|
||||
_rawCols: cols,
|
||||
_transformed: true,
|
||||
},
|
||||
// for when the legend header for the breakout is clicked
|
||||
clicked: {
|
||||
dimensions: [
|
||||
{
|
||||
value: breakoutValue,
|
||||
column: cols[seriesColumnIndex],
|
||||
},
|
||||
],
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
// dimensions.length <= 1
|
||||
const dimensionColumnIndex = dimensionColumnIndexes[0];
|
||||
return metricColumnIndexes.map(metricColumnIndex => {
|
||||
const col = cols[metricColumnIndex];
|
||||
const rowColumnIndexes = [dimensionColumnIndex].concat(
|
||||
metricColumnIndex,
|
||||
extraColumnIndexes,
|
||||
);
|
||||
const name = [
|
||||
// show series title if it's multiseries
|
||||
series.length > 1 && card.name,
|
||||
// show column name if there are multiple metrics or sigle series
|
||||
(metricColumnIndexes.length > 1 || series.length === 1) &&
|
||||
col &&
|
||||
getFriendlyName(col),
|
||||
]
|
||||
.filter(n => n)
|
||||
.join(": ");
|
||||
|
||||
return {
|
||||
card: {
|
||||
...card,
|
||||
name: name,
|
||||
originalCardName: card.name,
|
||||
_seriesIndex: seriesIndex,
|
||||
// use underlying column name as the seriesKey since it should be unique
|
||||
// EXCEPT for dashboard multiseries, so check seriesIndex == 0
|
||||
_seriesKey: seriesIndex === 0 && col ? col.name : name,
|
||||
},
|
||||
data: {
|
||||
rows: rows.map((row, rowIndex) => {
|
||||
const newRow = rowColumnIndexes.map(i => row[i]);
|
||||
newRow._origin = { seriesIndex, rowIndex, row, cols };
|
||||
return newRow;
|
||||
}),
|
||||
cols: rowColumnIndexes.map(i => cols[i]),
|
||||
results_timezone: data.results_timezone,
|
||||
_transformed: true,
|
||||
_rawCols: cols,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,17 @@
|
||||
import { t } from "ttag";
|
||||
import _ from "underscore";
|
||||
|
||||
import { formatValue } from "metabase/lib/formatting";
|
||||
import { getCardsColumns } from "metabase/visualizations/echarts/cartesian/model";
|
||||
import {
|
||||
getCardsSeriesModels,
|
||||
getDimensionModel,
|
||||
} from "metabase/visualizations/echarts/cartesian/model/series";
|
||||
import type {
|
||||
DimensionModel,
|
||||
SeriesModel,
|
||||
} from "metabase/visualizations/echarts/cartesian/model/types";
|
||||
import type { CartesianChartColumns } from "metabase/visualizations/lib/graph/columns";
|
||||
import { GRAPH_GOAL_SETTINGS } from "metabase/visualizations/lib/settings/goal";
|
||||
import {
|
||||
GRAPH_AXIS_SETTINGS,
|
||||
@@ -24,13 +35,23 @@ import type {
|
||||
VisualizationSettingsDefinitions,
|
||||
} from "metabase/visualizations/types";
|
||||
import { isDimension, isMetric } from "metabase-lib/v1/types/utils/isa";
|
||||
import type { RawSeries, SeriesSettings } from "metabase-types/api";
|
||||
import type {
|
||||
RawSeries,
|
||||
SeriesSettings,
|
||||
VisualizationSettings,
|
||||
} from "metabase-types/api";
|
||||
|
||||
import { transformSeries } from "./chart-definition-legacy";
|
||||
export type CartesianChartSettingsModel = {
|
||||
cardsColumns: CartesianChartColumns[];
|
||||
dimensionModel: DimensionModel;
|
||||
seriesModels: SeriesModel[];
|
||||
rawSeries: RawSeries;
|
||||
display: string;
|
||||
};
|
||||
|
||||
export const getCartesianChartDefinition = (
|
||||
props: Partial<Visualization>,
|
||||
): Partial<Visualization> => {
|
||||
props: Partial<Visualization<CartesianChartSettingsModel>>,
|
||||
): Partial<Visualization<CartesianChartSettingsModel>> => {
|
||||
return {
|
||||
noHeader: true,
|
||||
supportsSeries: true,
|
||||
@@ -82,7 +103,29 @@ export const getCartesianChartDefinition = (
|
||||
},
|
||||
] as RawSeries,
|
||||
|
||||
transformSeries,
|
||||
getSettingsModel: (
|
||||
rawSeries: RawSeries,
|
||||
settings: VisualizationSettings,
|
||||
): CartesianChartSettingsModel => {
|
||||
const cardsColumns = getCardsColumns(rawSeries, settings);
|
||||
const dimensionModel = getDimensionModel(rawSeries, cardsColumns);
|
||||
const seriesModels = getCardsSeriesModels(
|
||||
rawSeries,
|
||||
cardsColumns,
|
||||
settings,
|
||||
{
|
||||
formatValue: (value, options) => String(formatValue(value, options)),
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
cardsColumns,
|
||||
dimensionModel,
|
||||
seriesModels,
|
||||
rawSeries,
|
||||
display: rawSeries[0].card.display,
|
||||
};
|
||||
},
|
||||
|
||||
onDisplayUpdate: settings => {
|
||||
if (settings[SERIES_SETTING_KEY] == null) {
|
||||
|
||||
@@ -18,9 +18,9 @@ export function useChartDebug({
|
||||
chartModel: BaseCartesianChartModel;
|
||||
}) {
|
||||
useEffect(() => {
|
||||
if (!isQueryBuilder || !isChartsDebugLoggingEnabled) {
|
||||
return;
|
||||
}
|
||||
// if (!isQueryBuilder || !isChartsDebugLoggingEnabled) {
|
||||
// return;
|
||||
// }
|
||||
console.log("-------------- ECHARTS DEBUG INFO START --------------");
|
||||
console.log("rawSeries", rawSeries);
|
||||
console.log("option", option);
|
||||
|
||||
@@ -229,8 +229,7 @@ export const useChartEvents = (
|
||||
// all the data labels show
|
||||
const isBarSeries =
|
||||
seriesModel != null
|
||||
? settings.series(seriesModel.legacySeriesSettingsObjectKey)
|
||||
.display === "bar"
|
||||
? settings.series(seriesModel).display === "bar"
|
||||
: false;
|
||||
const shouldHighlightEntireSeries =
|
||||
isBarSeries && chartModel.seriesModels.length > 1;
|
||||
|
||||
@@ -256,6 +256,7 @@ class Table extends Component<TableProps, TableState> {
|
||||
column,
|
||||
settings,
|
||||
onChange,
|
||||
seriesModel,
|
||||
{
|
||||
series: [
|
||||
{
|
||||
@@ -282,6 +283,7 @@ class Table extends Component<TableProps, TableState> {
|
||||
column,
|
||||
settings,
|
||||
onChange,
|
||||
seriesModel,
|
||||
{
|
||||
series: [
|
||||
{
|
||||
|
||||
5
frontend/src/types/global.d.ts
vendored
5
frontend/src/types/global.d.ts
vendored
@@ -19,3 +19,8 @@ declare module "*.css" {
|
||||
}
|
||||
|
||||
type Nullable<T> = T | null;
|
||||
|
||||
type NonNullableProps<T, K extends keyof T> = Omit<T, K> &
|
||||
Required<{ [P in K]: NonNullable<T[P]> }>;
|
||||
|
||||
type $TODO = any;
|
||||
|
||||
Reference in New Issue
Block a user