diff --git a/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingColumns.jsx b/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingColumns.jsx index 0b798bfa10468f3a3306f1a384a93ba5008629b5..9034001f4bf6a0cbf98e5464c89f59f76f77bc23 100644 --- a/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingColumns.jsx +++ b/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingColumns.jsx @@ -1,3 +1,5 @@ +/* @flow */ + import React from "react"; import Icon from "metabase/components/Icon"; @@ -7,8 +9,12 @@ import ColumnItem from "./ColumnItem"; const displayNameForColumn = column => column ? column.display_name || column.name : "[Unknown]"; +import type { NestedSettingComponentProps } from "./ChartSettingNestedSettings"; + // various props injected by chartSettingNestedSettings HOC export default class ChartNestedSettingSeries extends React.Component { + props: NestedSettingComponentProps; + render() { const { objects, diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingNestedSettings.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingNestedSettings.jsx index 4b964efc5184443c53b8bb52cd701f783c704386..f45dd92c53da8c2b886303875892c8537dc7b398 100644 --- a/frontend/src/metabase/visualizations/components/settings/ChartSettingNestedSettings.jsx +++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingNestedSettings.jsx @@ -1,15 +1,66 @@ +/* @flow */ + import React from "react"; import ChartSettingsWidget from "../ChartSettingsWidget"; import _ from "underscore"; +import type { + Settings, + ExtraProps, + WidgetDef, +} from "metabase/visualizations/lib/settings"; +import type { + NestedObject, + NestedObjectKey, + SettingsWidgetsForObjectGetter, + NestedObjectKeyGetter, +} from "metabase/visualizations/lib/settings/nested"; +import type { Series } from "metabase/meta/types/Visualization"; + +export type NestedSettingComponentProps = { + objects: NestedObject[], + object: ?NestedObject, + objectSettingsWidgets: ?(WidgetDef[]), + onChangeEditingObject: (editingObject: ?NestedObject) => void, +}; +type NestedSettingComponent = Class< + React$Component<NestedSettingComponentProps, *, *>, +>; + +type SettingsByObjectKey = { [key: NestedObjectKey]: Settings }; + +type Props = { + value: SettingsByObjectKey, + onChange: (newSettings: SettingsByObjectKey) => void, + onEndEditing?: () => void, + series: Series, + extra: ExtraProps, + objects: NestedObject[], + initialKey?: NestedObjectKey, +}; + +type State = { + editingObjectKey: ?NestedObjectKey, +}; + +type ChartSettingsNestedSettingHOCProps = { + getObjectKey: NestedObjectKeyGetter, + getSettingsWidgetsForObject: SettingsWidgetsForObjectGetter, +}; + const chartSettingNestedSettings = ({ getObjectKey, getSettingsWidgetsForObject, -}) => ComposedComponent => +}: ChartSettingsNestedSettingHOCProps) => ( + ComposedComponent: NestedSettingComponent, +) => class extends React.Component { - constructor(props) { + props: Props; + state: State; + + constructor(props: Props) { super(props); this.state = { editingObjectKey: @@ -18,7 +69,7 @@ const chartSettingNestedSettings = ({ }; } - componentWillReceiveProps(nextProps) { + componentWillReceiveProps(nextProps: Props) { // reset editingObjectKey if there's only one object if ( nextProps.objects.length === 1 && @@ -30,7 +81,7 @@ const chartSettingNestedSettings = ({ } } - handleChangeEditingObject = editingObject => { + handleChangeEditingObject = (editingObject: ?NestedObject) => { this.setState({ editingObjectKey: editingObject ? getObjectKey(editingObject) : null, }); @@ -40,16 +91,27 @@ const chartSettingNestedSettings = ({ } }; - handleChangeSettingsForEditingObject = newSettings => { + handleChangeSettingsForEditingObject = (newSettings: Settings) => { const { editingObjectKey } = this.state; - this.handleChangeSettingsForObjectKey(editingObjectKey, newSettings); + if (editingObjectKey) { + this.handleChangeSettingsForObjectKey(editingObjectKey, newSettings); + } }; - handleChangeSettingsForObject = (object, newSettings) => { - this.handleChangeSettingsForObjectKey(getObjectKey(object), newSettings); + handleChangeSettingsForObject = ( + object: NestedObject, + newSettings: Settings, + ) => { + const objectKey = getObjectKey(object); + if (objectKey) { + this.handleChangeSettingsForObjectKey(objectKey, newSettings); + } }; - handleChangeSettingsForObjectKey = (objectKey, newSettings) => { + handleChangeSettingsForObjectKey = ( + objectKey: NestedObjectKey, + newSettings: Settings, + ) => { const { onChange } = this.props; const objectsSettings = this.props.value || {}; const objectSettings = objectsSettings[objectKey] || {}; @@ -65,43 +127,44 @@ const chartSettingNestedSettings = ({ render() { const { series, objects, extra } = this.props; const { editingObjectKey } = this.state; - const objectsSettings = this.props.value || {}; - const editingObject = _.find( - objects, - o => getObjectKey(o) === editingObjectKey, - ); - if (editingObject) { - const objectSettings = objectsSettings[editingObjectKey] || {}; - const objectSettingsWidgets = getSettingsWidgetsForObject( - series, - editingObject, - objectSettings, - this.handleChangeSettingsForEditingObject, - extra, - ); - return ( - <ComposedComponent - {...this.props} - getObjectKey={getObjectKey} - onChangeEditingObject={this.handleChangeEditingObject} - onChangeObjectSettings={this.handleChangeSettingsForObject} - object={editingObject} - objectSettingsWidgets={objectSettingsWidgets.map(widget => ( - <ChartSettingsWidget key={widget.id} {...widget} /> - ))} - /> - ); - } else { - return ( - <ComposedComponent - {...this.props} - getObjectKey={getObjectKey} - onChangeEditingObject={this.handleChangeEditingObject} - onChangeObjectSettings={this.handleChangeSettingsForObject} - /> + if (editingObjectKey) { + const editingObject = _.find( + objects, + o => getObjectKey(o) === editingObjectKey, ); + if (editingObject) { + const objectsSettings = this.props.value || {}; + const objectSettings = objectsSettings[editingObjectKey] || {}; + const objectSettingsWidgets = getSettingsWidgetsForObject( + series, + editingObject, + objectSettings, + this.handleChangeSettingsForEditingObject, + extra, + ); + return ( + <ComposedComponent + {...this.props} + getObjectKey={getObjectKey} + onChangeEditingObject={this.handleChangeEditingObject} + onChangeObjectSettings={this.handleChangeSettingsForObject} + object={editingObject} + objectSettingsWidgets={objectSettingsWidgets.map(widget => ( + <ChartSettingsWidget key={widget.id} {...widget} /> + ))} + /> + ); + } } + return ( + <ComposedComponent + {...this.props} + getObjectKey={getObjectKey} + onChangeEditingObject={this.handleChangeEditingObject} + onChangeObjectSettings={this.handleChangeSettingsForObject} + /> + ); } }; diff --git a/frontend/src/metabase/visualizations/lib/settings.js b/frontend/src/metabase/visualizations/lib/settings.js index da179387bbdd807c2fff42b1f87084c6f58bdcfd..048d0c28f971973e0711c3f3b5aa3733cc0a0181 100644 --- a/frontend/src/metabase/visualizations/lib/settings.js +++ b/frontend/src/metabase/visualizations/lib/settings.js @@ -23,8 +23,6 @@ export type SettingDefs = { }; export type SettingDef = { - id?: SettingId, - value?: any, title?: string, props?: { [key: string]: any }, default?: any, @@ -57,6 +55,8 @@ export type WidgetDef = { onChange: (value: any) => void, }; +export type ExtraProps = { [key: string]: any }; + const WIDGETS = { input: ChartSettingInput, inputGroup: ChartSettingInputGroup, @@ -75,7 +75,7 @@ export function getComputedSettings( settingsDefs: SettingDefs, object: any, storedSettings: Settings, - extra?: { [key: string]: any } = {}, + extra?: ExtraProps = {}, ) { const computedSettings = {}; for (let settingId in settingsDefs) { @@ -97,7 +97,7 @@ function getComputedSetting( settingId: SettingId, object: any, storedSettings: Settings, - extra?: { [key: string]: any } = {}, + extra?: ExtraProps = {}, ): any { if (settingId in computedSettings) { return; @@ -158,7 +158,7 @@ function getSettingWidget( settings: Settings, object: any, onChangeSettings: (settings: Settings) => void, - extra?: { [key: string]: any } = {}, + extra?: ExtraProps = {}, ): WidgetDef { const settingDef = settingDefs[settingId]; const value = settings[settingId]; @@ -204,7 +204,7 @@ export function getSettingsWidgets( settings: Settings, object: any, onChangeSettings: (settings: Settings) => void, - extra?: { [key: string]: any } = {}, + extra?: ExtraProps = {}, ) { return Object.keys(settingDefs) .map(settingId => diff --git a/frontend/src/metabase/visualizations/lib/settings/nested.js b/frontend/src/metabase/visualizations/lib/settings/nested.js index d414bc0dce69c4aad0a028a167b6b3386846ff51..73c9e5360d5fe0d8de4b122b917e0683f32f0bad 100644 --- a/frontend/src/metabase/visualizations/lib/settings/nested.js +++ b/frontend/src/metabase/visualizations/lib/settings/nested.js @@ -12,29 +12,42 @@ import type { SettingDef, SettingDefs, Settings, + WidgetDef, + ExtraProps, } from "metabase/visualizations/lib/settings"; import type { Series } from "metabase/meta/types/Visualization"; -type Object = any; +export type NestedObject = any; +export type NestedObjectKey = string; type NestedSettingDef = SettingDef & { objectName: string, - getObjects: (series: Series, settings: Settings) => Object[], - getObjectKey: (object: Object) => string, + getObjects: (series: Series, settings: Settings) => NestedObject[], + getObjectKey: (object: NestedObject) => string, getSettingDefintionsForObject: ( series: Series, - object: Object, + object: NestedObject, ) => SettingDefs, getObjectSettingsExtra?: ( series: Series, settings: Settings, - object: Object, + object: NestedObject, ) => { [key: string]: any }, component: React$Component<any, any, any>, id?: SettingId, }; +export type SettingsWidgetsForObjectGetter = ( + series: Series, + object: NestedObject, + storedSettings: Settings, + onChangeSettings: (newSettings: Settings) => void, + extra: ExtraProps, +) => WidgetDef[]; + +export type NestedObjectKeyGetter = (object: NestedObject) => NestedObjectKey; + export function nestedSettings( id: SettingId, { @@ -134,7 +147,7 @@ export function nestedSettings( [objectName]: { getDefault(series: Series, settings: Settings) { const cache = new Map(); - return (object: Object) => { + return (object: NestedObject) => { const key = getObjectKey(object); if (!cache.has(key)) { cache.set(key, { diff --git a/frontend/src/metabase/visualizations/visualizations/Table.jsx b/frontend/src/metabase/visualizations/visualizations/Table.jsx index dc4869f6078bb51f8686459164ad10b1a2abb779..4922f568fe3bae5b826cd41bd1c5061e0b5abcfe 100644 --- a/frontend/src/metabase/visualizations/visualizations/Table.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Table.jsx @@ -36,6 +36,7 @@ import { getIn } from "icepick"; import type { DatasetData } from "metabase/meta/types/Dataset"; import type { Card, VisualizationSettings } from "metabase/meta/types/Card"; +import type { SettingDefs } from "metabase/visualizations/lib/settings"; type Props = { card: Card, @@ -65,7 +66,7 @@ export default class Table extends Component { // scalar can always be rendered, nothing needed here } - static settings = { + static settings: SettingDefs = { ...columnSettings({ hidden: true }), "table.pivot": { section: t`Columns`,