diff --git a/frontend/src/metabase/dashboard/components/Dashboard.jsx b/frontend/src/metabase/dashboard/components/Dashboard.jsx index 45ed74ff52425ccaf5c6eda4677fbc8e1b523e29..d638ae3d20050db25d2edaadfcf2f69381552e5a 100644 --- a/frontend/src/metabase/dashboard/components/Dashboard.jsx +++ b/frontend/src/metabase/dashboard/components/Dashboard.jsx @@ -98,6 +98,7 @@ type Props = { refreshElapsed: number, isFullscreen: boolean, isNightMode: boolean, + hideParameters: ?string, onRefreshPeriodChange: (?number) => void, onNightModeChange: boolean => void, @@ -226,6 +227,7 @@ export default class Dashboard extends Component { location, isFullscreen, isNightMode, + hideParameters, } = this.props; let { error } = this.state; isNightMode = isNightMode && isFullscreen; @@ -238,6 +240,7 @@ export default class Dashboard extends Component { isEditing={isEditing} isFullscreen={isFullscreen} isNightMode={isNightMode} + hideParameters={hideParameters} parameters={parameters.map(p => ({ ...p, value: parameterValues[p.id], diff --git a/frontend/src/metabase/dashboard/hoc/DashboardControls.jsx b/frontend/src/metabase/dashboard/hoc/DashboardControls.jsx index 6a8318b676bd87732d3749f3996883ae50577cc1..8777448b1baacfa964ece6e42a56d8779402813e 100644 --- a/frontend/src/metabase/dashboard/hoc/DashboardControls.jsx +++ b/frontend/src/metabase/dashboard/hoc/DashboardControls.jsx @@ -26,6 +26,7 @@ type State = { isNightMode: boolean, refreshPeriod: ?number, refreshElapsed: ?number, + hideParameters: ?string, }; const TICK_PERIOD = 0.25; // seconds @@ -47,6 +48,8 @@ export default (ComposedComponent: ReactClass<any>) => refreshPeriod: null, refreshElapsed: null, + + hideParameters: null, }; _interval: ?number; @@ -88,6 +91,7 @@ export default (ComposedComponent: ReactClass<any>) => ); this.setNightMode(options.theme === "night" || options.night); // DEPRECATED: options.night this.setFullscreen(options.fullscreen); + this.setHideParameters(options.hide_parameters); }; updateDashboardParams = () => { @@ -164,6 +168,10 @@ export default (ComposedComponent: ReactClass<any>) => } }; + setHideParameters = parameters => { + this.setState({ hideParameters: parameters }); + }; + _tickRefreshClock = async () => { let refreshElapsed = (this.state.refreshElapsed || 0) + TICK_PERIOD; if ( diff --git a/frontend/src/metabase/parameters/components/Parameters.jsx b/frontend/src/metabase/parameters/components/Parameters.jsx index 98910f52ee035dcdb0643d270cb3fe4e670699e8..9fb3282e37534a34145469634db8f317c3ca1950 100644 --- a/frontend/src/metabase/parameters/components/Parameters.jsx +++ b/frontend/src/metabase/parameters/components/Parameters.jsx @@ -25,6 +25,7 @@ type Props = { isFullscreen?: boolean, isNightMode?: boolean, + hideParameters?: ?string, // comma separated list of slugs isEditing?: boolean, isQB?: boolean, vertical?: boolean, @@ -122,6 +123,7 @@ export default class Parameters extends Component { isEditing, isFullscreen, isNightMode, + hideParameters, isQB, setParameterName, setParameterValue, @@ -132,6 +134,8 @@ export default class Parameters extends Component { commitImmediately, } = this.props; + const hiddenParameters = new Set((hideParameters || "").split(",")); + const parameters = this._parametersWithValues(); let ParameterWidget; @@ -156,40 +160,42 @@ export default class Parameters extends Component { distance={9} onSortEnd={this.handleSortEnd} > - {parameters.map((parameter, index) => ( - <ParameterWidget - key={parameter.id} - index={index} - className={cx("relative hover-parent hover--visibility", { - mb2: vertical, - })} - isEditing={isEditing} - isFullscreen={isFullscreen} - isNightMode={isNightMode} - parameter={parameter} - parameters={parameters} - editingParameter={editingParameter} - setEditingParameter={setEditingParameter} - setName={ - setParameterName && (name => setParameterName(parameter.id, name)) - } - setValue={ - setParameterValue && - (value => setParameterValue(parameter.id, value)) - } - setDefaultValue={ - setParameterDefaultValue && - (value => setParameterDefaultValue(parameter.id, value)) - } - remove={removeParameter && (() => removeParameter(parameter.id))} - commitImmediately={commitImmediately} - > - {/* show drag handle if editing and setParameterIndex provided */} - {isEditing && setParameterIndex ? ( - <SortableParameterHandle /> - ) : null} - </ParameterWidget> - ))} + {parameters + .filter(p => !hiddenParameters.has(p.slug)) + .map((parameter, index) => ( + <ParameterWidget + key={parameter.id} + className={cx("relative hover-parent hover--visibility", { + mb2: vertical, + })} + isEditing={isEditing} + isFullscreen={isFullscreen} + isNightMode={isNightMode} + parameter={parameter} + parameters={parameters} + editingParameter={editingParameter} + setEditingParameter={setEditingParameter} + setName={ + setParameterName && + (name => setParameterName(parameter.id, name)) + } + setValue={ + setParameterValue && + (value => setParameterValue(parameter.id, value)) + } + setDefaultValue={ + setParameterDefaultValue && + (value => setParameterDefaultValue(parameter.id, value)) + } + remove={removeParameter && (() => removeParameter(parameter.id))} + commitImmediately={commitImmediately} + > + {/* show drag handle if editing and setParameterIndex provided */} + {isEditing && setParameterIndex ? ( + <SortableParameterHandle /> + ) : null} + </ParameterWidget> + ))} </ParameterWidgetList> ); } diff --git a/frontend/src/metabase/public/components/EmbedFrame.jsx b/frontend/src/metabase/public/components/EmbedFrame.jsx index 93a4ae4587f2dabc8a34c99d8ab967e4a7debf82..8ebd9d5a13adc03a447661408f94709f40a36c51 100644 --- a/frontend/src/metabase/public/components/EmbedFrame.jsx +++ b/frontend/src/metabase/public/components/EmbedFrame.jsx @@ -94,7 +94,7 @@ export default class EmbedFrame extends Component { const footer = true; - const { bordered, titled, theme } = { + const { bordered, titled, theme, hide_parameters } = { ...DEFAULT_OPTIONS, ...parseHashOptions(location.hash), }; @@ -127,6 +127,7 @@ export default class EmbedFrame extends Component { query={location.query} setParameterValue={setParameterValue} syncQueryString + hideParameters={hide_parameters} isQB /> </div> diff --git a/frontend/test/metabase/dashboard/dashboard.e2e.spec.js b/frontend/test/metabase/dashboard/dashboard.e2e.spec.js index 94df794401d43396b1fefd01ddd997f32a458bd4..30605f8f7861ce287c5b455b1ef982d23e4548ef 100644 --- a/frontend/test/metabase/dashboard/dashboard.e2e.spec.js +++ b/frontend/test/metabase/dashboard/dashboard.e2e.spec.js @@ -28,6 +28,7 @@ import { ParameterOptionItem, ParameterOptionsSection, } from "metabase/dashboard/components/ParametersPopover"; +import ParameterWidget from "metabase/parameters/components/ParameterWidget"; import ParameterValueWidget from "metabase/parameters/components/ParameterValueWidget"; import { PredefinedRelativeDatePicker } from "metabase/parameters/components/widgets/DateRelativeWidget"; import HeaderModal from "metabase/components/HeaderModal"; @@ -118,6 +119,14 @@ describe("Dashboard", () => { describe("dashboard page", () => { let dashboardId = null; + const checkDashboardWasCreated = () => { + if (!dashboardId) { + throw new Error( + "Test fails because previous tests failed to create a dashboard", + ); + } + }; + it("lets you change title and description", async () => { const name = "Customer Feedback Analysis"; const description = @@ -152,11 +161,7 @@ describe("Dashboard", () => { }); it("lets you add a filter", async () => { - if (!dashboardId) { - throw new Error( - "Test fails because previous tests failed to create a dashboard", - ); - } + checkDashboardWasCreated(); const store = await createTestStore(); store.pushPath(Urls.dashboard(dashboardId)); @@ -195,14 +200,36 @@ describe("Dashboard", () => { // Wait until the header modal exit animation is finished await store.waitForActions([SET_EDITING_PARAMETER_ID]); + + // save + clickButton(app.find(".Button.Button--small.Button--primary")); + await store.waitForActions([FETCH_DASHBOARD]); + }); + + it("shows previously added parameter", async () => { + checkDashboardWasCreated(); + + const store = await createTestStore(); + const dashboardUrl = Urls.dashboard(dashboardId); + store.pushPath(dashboardUrl); + const app = mount(store.getAppContainer()); + await store.waitForActions([FETCH_DASHBOARD]); + expect(app.find(ParameterWidget)).toHaveLength(1); + }); + + it("hides parameters named in 'hide_parameters' option", async () => { + checkDashboardWasCreated(); + + const store = await createTestStore(); + const dashboardUrl = Urls.dashboard(dashboardId); + store.pushPath(dashboardUrl + "#hide_parameters=relative_date"); + const app = mount(store.getAppContainer()); + await store.waitForActions([FETCH_DASHBOARD]); + expect(app.find(ParameterWidget)).toHaveLength(0); }); it("lets you open and close the revisions screen", async () => { - if (!dashboardId) { - throw new Error( - "Test fails because previous tests failed to create a dashboard", - ); - } + checkDashboardWasCreated(); const store = await createTestStore(); const dashboardUrl = Urls.dashboard(dashboardId); @@ -226,6 +253,8 @@ describe("Dashboard", () => { }); it("lets you go directly to the revisions screen via url", async () => { + checkDashboardWasCreated(); + const store = await createTestStore(); const dashboardUrl = Urls.dashboard(dashboardId); store.pushPath(dashboardUrl + `/history`);