Skip to content
Snippets Groups Projects
Unverified Commit ecce3838 authored by Nicolò Pretto's avatar Nicolò Pretto Committed by GitHub
Browse files

convert embed.ts to ts and to use createSlice from rtk (#44496)

* convert embed.ts to use createSlice from rtk

* only store in the state what we care about for interactive embedding

* use DEFAULT_EMBED_OPTIONS keys to filter searchOptions

* removed unused hash parameter

* adds basic unit test
parent 0637fefa
No related branches found
No related tags found
No related merge requests found
import { parseHashOptions, parseSearchOptions } from "metabase/lib/browser";
import {
combineReducers,
createAction,
handleActions,
} from "metabase/lib/redux";
import { createSlice, type PayloadAction } from "@reduxjs/toolkit";
import { pick } from "underscore";
import { parseSearchOptions } from "metabase/lib/browser";
import type { EmbedOptions } from "metabase-types/store";
export const DEFAULT_EMBED_OPTIONS = {
export const DEFAULT_EMBED_OPTIONS: EmbedOptions = {
top_nav: true,
side_nav: "default",
search: false,
......@@ -18,42 +16,50 @@ export const DEFAULT_EMBED_OPTIONS = {
action_buttons: true,
} as const;
export const SET_INITIAL_URL_OPTIONS = "metabase/embed/SET_INITIAL_URL_OPTIONS";
export const setInitialUrlOptions = createAction(
SET_INITIAL_URL_OPTIONS,
({ search, hash }: { search: string; hash: string }) => {
return {
...parseSearchOptions(search),
...parseHashOptions(hash),
};
const allowedEmbedOptions = Object.keys(DEFAULT_EMBED_OPTIONS);
export const urlParameterToBoolean = (
urlParameter: string | string[] | boolean | undefined,
) => {
if (urlParameter === undefined) {
return undefined;
}
if (Array.isArray(urlParameter)) {
return Boolean(urlParameter.at(-1));
} else {
return Boolean(urlParameter);
}
};
const interactiveEmbedSlice = createSlice({
name: "interactiveEmbed",
initialState: {
options: {} as EmbedOptions,
isEmbeddingSdk: false,
},
);
export const SET_OPTIONS = "metabase/embed/SET_OPTIONS";
export const setOptions = createAction(
SET_OPTIONS,
(options: Partial<EmbedOptions>) => options,
);
const options = handleActions(
{
[SET_INITIAL_URL_OPTIONS]: (state, { payload }) => ({
...DEFAULT_EMBED_OPTIONS,
...payload,
}),
[SET_OPTIONS]: (state, { payload }) => ({
...state,
...payload,
}),
reducers: {
setInitialUrlOptions: (
state,
action: PayloadAction<{ search: string }>,
) => {
const searchOptions = parseSearchOptions(action.payload.search);
state.options = {
...DEFAULT_EMBED_OPTIONS,
...pick(searchOptions, allowedEmbedOptions),
};
},
setOptions: (state, action: PayloadAction<Partial<EmbedOptions>>) => {
state.options = {
...state.options,
...action.payload,
};
},
},
{},
);
});
const isEmbeddingSdk = handleActions({}, false);
export const { setInitialUrlOptions, setOptions } =
interactiveEmbedSlice.actions;
// eslint-disable-next-line import/no-default-export -- deprecated usage
export default combineReducers({
options,
isEmbeddingSdk,
});
// eslint-disable-next-line import/no-default-export
export default interactiveEmbedSlice.reducer;
import { configureStore, type Dispatch } from "@reduxjs/toolkit";
import embedReduer, {
DEFAULT_EMBED_OPTIONS,
setInitialUrlOptions,
} from "./embed";
describe("embed reducer", () => {
describe("setInitialUrlOptions", () => {
it("should set default options", () => {
const store = createMockStore();
store.dispatch(setInitialUrlOptions({ search: "" }));
expect(store.getState().embed.options).toEqual(DEFAULT_EMBED_OPTIONS);
});
it("should set options from search", () => {
const store = createMockStore();
store.dispatch(
setInitialUrlOptions({ search: "top_nav=false&new_button=true" }),
);
expect(store.getState().embed.options.top_nav).toBe(false);
expect(store.getState().embed.options.new_button).toBe(true);
});
it("should ignore invalid options", () => {
const store = createMockStore();
store.dispatch(
setInitialUrlOptions({ search: "top_nav=false&invalid_option=123" }),
);
expect(store.getState().embed.options).not.toHaveProperty(
"invalid_option",
);
});
});
});
const createMockStore = () => {
const store = configureStore({
reducer: { embed: embedReduer },
});
return store as typeof store & { dispatch: Dispatch };
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment