Merge branch 'feature/page-params' into 'release'

Page Params

See merge request theappsmith/internal-tools-client!430
This commit is contained in:
Satbir Singh 2020-04-01 08:09:57 +00:00
commit 292aa713f9
9 changed files with 410 additions and 249 deletions

View File

@ -94,7 +94,8 @@
"toposort": "^2.0.2",
"ts-loader": "^6.0.4",
"typescript": "^3.6.3",
"unescape-js": "^1.1.4"
"unescape-js": "^1.1.4",
"url-search-params-polyfill": "^8.0.0"
},
"scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js'",

View File

@ -10,6 +10,7 @@ import StyledDropdown from "components/editorComponents/StyledDropdown";
import { ActionDataState } from "reducers/entityReducers/actionsReducer";
import { getModalDropdownList } from "selectors/widgetSelectors";
import { getActionsForCurrentPage } from "selectors/entitiesSelector";
import { KeyValueComponent } from "components/propertyControls/KeyValueComponent";
import { createModalAction } from "actions/widgetActions";
const ACTION_TRIGGER_REGEX = /^{{([\s\S]*?)\(([\s\S]*?)\)}}$/g;
@ -22,7 +23,12 @@ const ALERT_STYLE_OPTIONS = [
{ label: "Warning", value: "'warning'", id: "warning" },
];
type ValueChangeHandler = (changeValue: string, currentValue: string) => string;
type ValueType = string | DropdownOption[];
type ValueChangeHandler = (
changeValue: ValueType,
currentValue: string,
) => string;
type ActionCreatorArgumentConfig = {
label: string;
field: string;
@ -31,7 +37,7 @@ type ActionCreatorArgumentConfig = {
dispatchPayload: ReduxActionWithoutPayload;
};
valueChangeHandler: ValueChangeHandler;
getSelectedValue: (value: string, returnArguments: boolean) => string;
getSelectedValue: (value: string, returnArguments: boolean) => ValueType;
};
interface ActionCreatorDropdownOption extends DropdownOption {
@ -39,7 +45,7 @@ interface ActionCreatorDropdownOption extends DropdownOption {
}
const handleTopLevelFuncUpdate: ValueChangeHandler = (
value: string,
value: ValueType,
): string => {
return value === "none" ? "" : `{{${value}()}}`;
};
@ -69,19 +75,46 @@ const handleApiArgSelect = (
);
};
const handlePageNameArgSelect = (changeValue: string, currentValue: string) => {
return currentValue.replace(ACTION_TRIGGER_REGEX, `{{$1(${changeValue})}}`);
const handlePageNameArgSelect = (
changeValue: ValueType,
currentValue: string,
) => {
const matches = [...currentValue.matchAll(ACTION_TRIGGER_REGEX)];
const args = matches[0][2].split(",");
args[0] = `${changeValue}`;
return currentValue.replace(
ACTION_TRIGGER_REGEX,
`{{$1(${args.join(",")})}}`,
);
};
const handlePageParamsArgSelect = (
changeValue: ValueType,
currentValue: string,
) => {
const matches = [...currentValue.matchAll(ACTION_TRIGGER_REGEX)];
const args = matches[0][2].split(",").slice(0, 2);
const paramsObject: Record<string, string> = {};
(changeValue as DropdownOption[]).forEach(pageParam => {
paramsObject[pageParam.label] = pageParam.value;
});
args[1] = JSON.stringify(paramsObject);
return currentValue.replace(
ACTION_TRIGGER_REGEX,
`{{$1(${args.join(",")})}}`,
);
};
const handleTextArgChange = (
changeValue: string,
changeValue: ValueType,
currentValue: string,
): string => {
return currentValue.replace(ACTION_TRIGGER_REGEX, `{{$1('${changeValue}')}}`);
};
const handleAlertTextChange = (
changeValue: string,
changeValue: ValueType,
currentValue: string,
): string => {
const matches = [...currentValue.matchAll(ACTION_TRIGGER_REGEX)];
@ -95,12 +128,12 @@ const handleAlertTextChange = (
};
const handleAlertTypeChange = (
changeValue: string,
changeValue: ValueType,
currentValue: string,
): string => {
const matches = [...currentValue.matchAll(ACTION_TRIGGER_REGEX)];
const args = matches[0][2].split(",");
args[1] = changeValue;
args[1] = changeValue as string;
return currentValue.replace(
ACTION_TRIGGER_REGEX,
`{{$1(${args.join(",")})}}`,
@ -131,7 +164,36 @@ const getApiArgumentValue = (
const getPageNameSelectedValue = (value: string) => {
const matches = [...value.matchAll(ACTION_TRIGGER_REGEX)];
return matches.length ? matches[0][2] : "none";
return matches.length ? matches[0][2].split(",")[0] : "none";
};
const getPageParamsSelectedValue = (value: ValueType) => {
const match = getPageSelectedParamsObject(value as string);
const keyPairs: DropdownOption[] = [];
Object.keys(match).forEach((key: string) => {
keyPairs.push({
label: key,
value: match[key],
});
});
return keyPairs;
};
const getPageSelectedParamsObject = (value: string) => {
const matches = [...value.matchAll(ACTION_TRIGGER_REGEX)];
let match: Record<string, string> = {};
if (matches.length) {
try {
match = JSON.parse(
matches[0][2].substring(
matches[0][2].indexOf(",") + 1,
matches[0][2].length,
),
);
} catch {}
}
return match;
};
export const getTextArgValue = (value: string) => {
@ -179,7 +241,7 @@ export const PropertyPaneActionDropdownOptions: ActionCreatorDropdownOption[] =
label: "onSuccess",
field: "ACTION_SELECTOR_FIELD",
valueChangeHandler: (changeValue, currentValue) =>
handleApiArgSelect(changeValue, currentValue, "onSuccess"),
handleApiArgSelect(changeValue as string, currentValue, "onSuccess"),
getSelectedValue: (value: string, returnArgs = false) =>
getApiArgumentValue(value, "onSuccess", returnArgs),
},
@ -187,7 +249,7 @@ export const PropertyPaneActionDropdownOptions: ActionCreatorDropdownOption[] =
label: "onError",
field: "ACTION_SELECTOR_FIELD",
valueChangeHandler: (changeValue, currentValue) =>
handleApiArgSelect(changeValue, currentValue, "onError"),
handleApiArgSelect(changeValue as string, currentValue, "onError"),
getSelectedValue: (value: string, returnArgs = false) =>
getApiArgumentValue(value, "onError", returnArgs),
},
@ -234,6 +296,12 @@ export const PropertyPaneActionDropdownOptions: ActionCreatorDropdownOption[] =
valueChangeHandler: handlePageNameArgSelect,
getSelectedValue: getPageNameSelectedValue,
},
{
label: "params",
field: "KEY_VALUE_FIELD",
valueChangeHandler: handlePageParamsArgSelect,
getSelectedValue: getPageParamsSelectedValue,
},
],
},
{
@ -298,15 +366,18 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
};
handleValueUpdate = (
updateValueOrEvent: string | ChangeEvent<HTMLTextAreaElement>,
updateValueOrEvent: ValueType | ChangeEvent<HTMLTextAreaElement>,
valueUpdateHandler: ValueChangeHandler,
) => {
const { value, onValueChange } = this.props;
let updateValue = updateValueOrEvent;
if (typeof updateValueOrEvent !== "string") {
updateValue = updateValueOrEvent.target.value;
if (
typeof updateValueOrEvent !== "string" &&
(updateValueOrEvent as any).target
) {
updateValue = (updateValueOrEvent as any).target.value;
}
const newValue = valueUpdateHandler(updateValue as string, value);
const newValue = valueUpdateHandler(updateValue as ValueType, value);
onValueChange(newValue);
};
@ -314,7 +385,7 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
argValue: string,
allOptions: ActionCreatorDropdownOption[],
parentChangeHandler: (
updateValueOrEvent: string | ChangeEvent<HTMLTextAreaElement>,
updateValueOrEvent: ValueType | ChangeEvent<HTMLTextAreaElement>,
valueUpdateHandler: ValueChangeHandler,
) => void,
argumentConfig: ActionCreatorArgumentConfig,
@ -330,15 +401,18 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
}
});
const handleValueUpdate = (
updateValueOrEvent: string | ChangeEvent<HTMLTextAreaElement>,
updateValueOrEvent: ValueType | ChangeEvent<HTMLTextAreaElement>,
valueUpdateHandler: ValueChangeHandler,
) => {
let updateValue = updateValueOrEvent;
if (typeof updateValueOrEvent !== "string") {
updateValue = updateValueOrEvent.target.value;
if (
typeof updateValueOrEvent !== "string" &&
(updateValueOrEvent as any).target
) {
updateValue = (updateValueOrEvent as any).target.value;
}
const tempArg = `{{${subArgValue}${subArguments}}}`;
const newValue = valueUpdateHandler(updateValue as string, tempArg);
const newValue = valueUpdateHandler(updateValue as ValueType, tempArg);
const newArgValue = newValue.substring(2, newValue.length - 2);
parentChangeHandler(newArgValue, argumentConfig.valueChangeHandler);
};
@ -356,7 +430,7 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
selectedOption: ActionCreatorDropdownOption,
allOptions: ActionCreatorDropdownOption[],
handleUpdate: (
updateValueOrEvent: string | ChangeEvent<HTMLTextAreaElement>,
updateValueOrEvent: ValueType | ChangeEvent<HTMLTextAreaElement>,
valueUpdateHandler: ValueChangeHandler,
) => void,
) => {
@ -370,7 +444,7 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
<label>{arg.label}</label>
<StyledDropdown
options={allOptions}
selectedValue={arg.getSelectedValue(value, false)}
selectedValue={arg.getSelectedValue(value, false) as string}
defaultText={"Select Action"}
onSelect={value =>
handleUpdate(value, arg.valueChangeHandler)
@ -390,11 +464,25 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
<label>{arg.label}</label>
<StyledDropdown
options={this.props.pageNameDropdown}
selectedValue={arg.getSelectedValue(value, false)}
selectedValue={arg.getSelectedValue(value, false) as string}
defaultText={"Select Page"}
onSelect={value =>
handleUpdate(value, arg.valueChangeHandler)
onSelect={newValue => {
handleUpdate(newValue, arg.valueChangeHandler);
}}
/>
</ControlWrapper>
);
case "KEY_VALUE_FIELD":
return (
<ControlWrapper key={arg.label}>
<KeyValueComponent
pairs={
arg.getSelectedValue(value, false) as DropdownOption[]
}
addLabel={"QueryParam"}
updatePairs={(pageParams: DropdownOption[]) => {
handleUpdate(pageParams as any, arg.valueChangeHandler);
}}
/>
</ControlWrapper>
);
@ -404,7 +492,7 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
<label>{arg.label}</label>
<StyledDropdown
options={this.props.modalDropdown || []}
selectedValue={arg.getSelectedValue(value, false)}
selectedValue={arg.getSelectedValue(value, false) as string}
defaultText={"Select Modal"}
createButton={
arg.create && {
@ -426,7 +514,7 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
<label>{arg.label}</label>
<InputText
label={arg.label}
value={arg.getSelectedValue(value, false)}
value={arg.getSelectedValue(value, false) as string}
onChange={e => handleUpdate(e, arg.valueChangeHandler)}
isValid={this.props.isValid}
validationMessage={this.props.validationMessage}
@ -440,7 +528,7 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
<StyledDropdown
options={ALERT_STYLE_OPTIONS}
defaultText={"Select type"}
selectedValue={arg.getSelectedValue(value, false)}
selectedValue={arg.getSelectedValue(value, false) as string}
onSelect={value =>
handleUpdate(value, arg.valueChangeHandler)
}

View File

@ -0,0 +1,179 @@
import React, { useState, useEffect } from "react";
import styled from "constants/DefaultTheme";
import { FormIcons } from "icons/FormIcons";
import { AnyStyledComponent } from "styled-components";
import {
ControlWrapper,
StyledInputGroup,
StyledPropertyPaneButton,
} from "./StyledControls";
import { DropDownOptionWithKey } from "./OptionControl";
import { DropdownOption } from "widgets/DropdownWidget";
import { generateReactKey } from "utils/generators";
function updateOptionLabel<T>(
options: Array<T>,
index: number,
updatedLabel: string,
) {
return options.map((option: T, optionIndex) => {
if (index !== optionIndex) {
return option;
}
return {
...option,
label: updatedLabel,
};
});
}
function updateOptionValue<T>(
options: Array<T>,
index: number,
updatedValue: string,
) {
return options.map((option, optionIndex) => {
if (index !== optionIndex) {
return option;
}
return {
...option,
value: updatedValue,
};
});
}
const StyledDeleteIcon = styled(FormIcons.DELETE_ICON as AnyStyledComponent)`
padding: 0px 5px;
position: absolute;
right: -2px;
cursor: pointer;
`;
const StyledOptionControlInputGroup = styled(StyledInputGroup)`
margin-right: 2px;
`;
const StyledOptionControlWrapper = styled(ControlWrapper)`
display: flex;
justify-content: flex-start;
padding-right: 16px;
`;
type KeyValueComponentProps = {
pairs: DropdownOption[];
updatePairs: Function;
addLabel?: string;
};
export function KeyValueComponent(props: KeyValueComponentProps) {
const [renderPairs, setRenderPairs] = useState<DropDownOptionWithKey[]>([]);
const { pairs } = props;
useEffect(() => {
let { pairs } = props;
pairs = Array.isArray(pairs) ? pairs.slice() : [];
const newRenderPairs: DropDownOptionWithKey[] = pairs.map(pair => {
return {
...pair,
key: generateReactKey(),
};
});
pairs.length !== 0 &&
renderPairs.length === 0 &&
setRenderPairs(newRenderPairs);
}, [props, pairs.length, renderPairs.length]);
function deletePair(index: number) {
let { pairs } = props;
pairs = Array.isArray(pairs) ? pairs : [];
const newPairs = pairs.filter((o, i) => i !== index);
const newRenderPairs = renderPairs.filter((o, i) => i !== index);
setRenderPairs(newRenderPairs);
props.updatePairs(newPairs);
}
function updateKey(index: number, updatedKey: string) {
let { pairs } = props;
pairs = Array.isArray(pairs) ? pairs : [];
const updatedPairs = updateOptionLabel(pairs, index, updatedKey);
const updatedRenderPairs = updateOptionLabel(
renderPairs,
index,
updatedKey,
);
setRenderPairs(updatedRenderPairs);
props.updatePairs(updatedPairs);
}
function updateValue(index: number, updatedValue: string) {
let { pairs } = props;
pairs = Array.isArray(pairs) ? pairs : [];
const updatedPairs = updateOptionValue(pairs, index, updatedValue);
const updatedRenderPairs = updateOptionValue(
renderPairs,
index,
updatedValue,
);
setRenderPairs(updatedRenderPairs);
props.updatePairs(updatedPairs);
}
function addPair() {
let { pairs } = props;
pairs = Array.isArray(pairs) ? pairs.slice() : [];
pairs.push({ label: "", value: "" });
const updatedRenderPairs = renderPairs.slice();
updatedRenderPairs.push({ label: "", value: "", key: generateReactKey() });
setRenderPairs(updatedRenderPairs);
props.updatePairs(pairs);
}
return (
<React.Fragment>
{renderPairs.map((pair: DropDownOptionWithKey, index) => {
return (
<StyledOptionControlWrapper orientation={"HORIZONTAL"} key={pair.key}>
<StyledOptionControlInputGroup
type={"text"}
placeholder={"Name"}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
updateKey(index, event.target.value);
}}
defaultValue={pair.label}
/>
<StyledOptionControlInputGroup
type={"text"}
placeholder={"Value"}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
updateValue(index, event.target.value);
}}
defaultValue={pair.value}
/>
<StyledDeleteIcon
height={20}
width={20}
onClick={() => {
deletePair(index);
}}
/>
</StyledOptionControlWrapper>
);
})}
<StyledPropertyPaneButton
text={props.addLabel || "Option"}
icon={"plus"}
color={"#FFFFFF"}
minimal={true}
onClick={addPair}
/>
</React.Fragment>
);
}

View File

@ -1,223 +1,24 @@
import React from "react";
import BaseControl, { ControlProps } from "./BaseControl";
import {
ControlWrapper,
StyledInputGroup,
StyledPropertyPaneButton,
} from "./StyledControls";
import { DropdownOption } from "widgets/DropdownWidget";
import { ControlType } from "constants/PropertyControlConstants";
import styled from "constants/DefaultTheme";
import { FormIcons } from "icons/FormIcons";
import { AnyStyledComponent } from "styled-components";
import { generateReactKey } from "utils/generators";
import { KeyValueComponent } from "./KeyValueComponent";
const StyledDeleteIcon = styled(FormIcons.DELETE_ICON as AnyStyledComponent)`
padding: 5px 5px;
position: absolute;
right: -4px;
cursor: pointer;
`;
const StyledOptionControlInputGroup = styled(StyledInputGroup)`
margin-right: 2px;
`;
const StyledOptionControlWrapper = styled(ControlWrapper)`
display: flex;
justify-content: flex-start;
padding-right: 16px;
`;
function updateOptionLabel<T>(
options: Array<T>,
index: number,
updatedLabel: string,
) {
return options.map((option: T, optionIndex) => {
if (index !== optionIndex) {
return option;
}
return {
...option,
label: updatedLabel,
};
});
}
function updateOptionValue<T>(
options: Array<T>,
index: number,
updatedValue: string,
) {
return options.map((option, optionIndex) => {
if (index !== optionIndex) {
return option;
}
return {
...option,
value: updatedValue,
};
});
}
type DropDownOptionWithKey = DropdownOption & {
export type DropDownOptionWithKey = DropdownOption & {
key: string;
};
class OptionControl extends BaseControl<
ControlProps,
{
renderOptions: DropDownOptionWithKey[];
}
> {
constructor(props: ControlProps) {
super(props);
this.state = {
renderOptions: [],
};
}
class OptionControl extends BaseControl<ControlProps> {
render() {
const { renderOptions } = this.state;
return (
<React.Fragment>
{renderOptions.map((option, index) => {
return (
<StyledOptionControlWrapper
orientation={"HORIZONTAL"}
key={option.key}
>
<StyledOptionControlInputGroup
type={"text"}
placeholder={"Name"}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
this.updateOptionLabel(index, event.target.value);
}}
defaultValue={option.label}
/>
<StyledOptionControlInputGroup
type={"text"}
placeholder={"Value"}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
this.updateOptionValue(index, event.target.value);
}}
defaultValue={option.value}
/>
<StyledDeleteIcon
height={20}
width={20}
onClick={() => {
this.deleteOption(index);
}}
/>
</StyledOptionControlWrapper>
);
})}
<StyledPropertyPaneButton
text={"Option"}
icon={"plus"}
color={"#FFFFFF"}
minimal={true}
onClick={this.addOption}
/>
</React.Fragment>
<KeyValueComponent
pairs={this.props.propertyValue}
updatePairs={this.updateOptions}
/>
);
}
componentDidMount() {
const { propertyValue } = this.props;
const options: DropdownOption[] = Array.isArray(propertyValue)
? propertyValue
: [{}];
options.map(option => {
return {
...option,
key: generateReactKey(),
};
});
this.setState({
renderOptions: options.map(option => {
return {
...option,
key: generateReactKey(),
};
}),
});
}
deleteOption = (index: number) => {
const { propertyValue } = this.props;
const options: DropdownOption[] = Array.isArray(propertyValue)
? propertyValue
: [{}];
const { renderOptions } = this.state;
const newOptions = options.filter((o, i) => i !== index);
const newRenderOptions = renderOptions.filter((o, i) => i !== index);
this.updateProperty("options", newOptions);
this.setState({
renderOptions: newRenderOptions,
});
};
updateOptionLabel = (index: number, updatedLabel: string) => {
const { propertyValue } = this.props;
const options: DropdownOption[] = Array.isArray(propertyValue)
? propertyValue
: [{}];
this.updateProperty(
"options",
updateOptionLabel(options, index, updatedLabel),
);
this.setState({
renderOptions: updateOptionLabel(
this.state.renderOptions,
index,
updatedLabel,
),
});
};
updateOptionValue = (index: number, updatedValue: string) => {
const { propertyValue } = this.props;
const options: DropdownOption[] = Array.isArray(propertyValue)
? propertyValue
: [{}];
this.updateProperty(
"options",
updateOptionValue(options, index, updatedValue),
);
this.setState({
renderOptions: updateOptionValue(
this.state.renderOptions,
index,
updatedValue,
),
});
};
addOption = () => {
const { propertyValue } = this.props;
const options: DropdownOption[] = Array.isArray(propertyValue)
? propertyValue
: [{}];
const { renderOptions } = this.state;
options.push({ label: "", value: "" });
renderOptions.push({
label: "",
value: "",
key: generateReactKey(),
});
this.setState({
renderOptions: renderOptions,
});
updateOptions = (options: DropdownOption[]) => {
this.updateProperty("options", options);
};

View File

@ -28,9 +28,13 @@ export const BUILDER_BASE_URL = (applicationId = ":applicationId"): string =>
export const BUILDER_PAGE_URL = (
applicationId?: string,
pageId?: string,
params?: Record<string, string>,
): string => {
if (!pageId) return APPLICATIONS_URL;
return `${BUILDER_BASE_URL(applicationId)}/pages/${pageId}/edit`;
const queryParams = convertToQueryParams(params);
return (
`${BUILDER_BASE_URL(applicationId)}/pages/${pageId}/edit` + queryParams
);
};
export const API_EDITOR_URL = (
@ -58,7 +62,26 @@ export const getApplicationViewerURL = (
export const getApplicationViewerPageURL = (
applicationId = ":applicationId",
pageId = ":pageId",
): string => `/applications/${applicationId}/pages/${pageId}`;
params: Record<string, string> = {},
): string => {
const url = `/applications/${applicationId}/pages/${pageId}`;
const queryParams = convertToQueryParams(params);
return url + queryParams;
};
function convertToQueryParams(params: Record<string, string> = {}): string {
const paramKeys = Object.keys(params);
let queryParams = "";
if (paramKeys) {
paramKeys.forEach((paramKey: string, index: number) => {
const value = params[paramKey];
if (paramKey && value) {
queryParams = queryParams + `&${paramKey}=${value}`;
}
});
}
return queryParams ? "?" + queryParams : "";
}
export const EDITOR_ROUTES = [
{

View File

@ -33,6 +33,17 @@ export interface DataTreeAction extends Omit<ActionData, "data"> {
ENTITY_TYPE: ENTITY_TYPE.ACTION;
}
export interface DataTreeUrl {
queryParams: Record<string, string>;
protocol: string;
host: string;
hostname: string;
port: string;
pathname: string;
hash: string;
href: string;
}
export interface DataTreeWidget extends WidgetProps {
ENTITY_TYPE: ENTITY_TYPE.WIDGET;
}
@ -40,6 +51,7 @@ export interface DataTreeWidget extends WidgetProps {
export type DataTreeEntity =
| DataTreeAction
| DataTreeWidget
| DataTreeUrl
| ActionDispatcher<any, any>;
export type DataTree = {
@ -50,10 +62,16 @@ type DataTreeSeed = {
actions: ActionDataState;
widgets: CanvasWidgetsReduxState;
widgetsMeta: MetaState;
url: DataTreeUrl;
};
export class DataTreeFactory {
static create({ actions, widgets, widgetsMeta }: DataTreeSeed): DataTree {
static create({
actions,
widgets,
widgetsMeta,
url,
}: DataTreeSeed): DataTree {
const dataTree: DataTree = {};
dataTree.actionPaths = [
"navigateTo",
@ -89,10 +107,10 @@ export class DataTreeFactory {
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
};
});
dataTree.navigateTo = function(pageName: string) {
dataTree.navigateTo = function(pageName: string, params: object) {
return {
type: "NAVIGATE_TO",
payload: { pageName },
payload: { pageName, params },
};
};
@ -110,6 +128,7 @@ export class DataTreeFactory {
};
};
dataTree.url = url;
dataTree.showModal = function(modalName: string) {
return {
type: "SHOW_MODAL_BY_NAME",

View File

@ -264,7 +264,7 @@ export function* executeActionSaga(
}
function* navigateActionSaga(
action: { pageName: string },
action: { pageName: string; params: Record<string, string> },
event: ExecuteActionPayloadEvent,
) {
const pageList = yield select(getPageList);
@ -272,9 +272,14 @@ function* navigateActionSaga(
const page = _.find(pageList, { pageName: action.pageName });
if (page) {
// TODO need to make this check via RENDER_MODE;
const path = history.location.pathname.endsWith("/edit")
? BUILDER_PAGE_URL(applicationId, page.pageId)
: getApplicationViewerPageURL(applicationId, page.pageId);
const path =
history.location.pathname.indexOf("/edit") !== -1
? BUILDER_PAGE_URL(applicationId, page.pageId, action.params)
: getApplicationViewerPageURL(
applicationId,
page.pageId,
action.params,
);
history.push(path);
if (event.callback) event.callback({ success: true });
} else {
@ -293,6 +298,7 @@ export function* executeActionTriggers(
case "NAVIGATE_TO":
AnalyticsUtil.logEvent("NAVIGATE", {
pageName: trigger.payload.pageName,
pageParams: trigger.payload.pageParams,
});
yield call(navigateActionSaga, trigger.payload, event);
break;

View File

@ -3,17 +3,56 @@ import { getActionsForCurrentPage } from "./entitiesSelector";
import { ActionDataState } from "reducers/entityReducers/actionsReducer";
import { getEvaluatedDataTree } from "utils/DynamicBindingUtils";
import { extraLibraries } from "jsExecution/JSExecutionManagerSingleton";
import { DataTree, DataTreeFactory } from "entities/DataTree/dataTreeFactory";
import {
DataTree,
DataTreeFactory,
DataTreeUrl,
} from "entities/DataTree/dataTreeFactory";
import _ from "lodash";
import { getWidgets, getWidgetsMeta } from "sagas/selectors";
import * as log from "loglevel";
import "url-search-params-polyfill";
function getQueryParams() {
const urlParams = new URLSearchParams(window.location.search);
const keys = urlParams.keys();
let key = keys.next().value;
const queryParams: Record<string, string> = {};
while (key) {
queryParams[key] = urlParams.get(key) as string;
key = keys.next().value;
}
return queryParams;
}
const getUrlParams = createSelector(
getQueryParams,
(queryParams: Record<string, string>): DataTreeUrl => {
return {
host: window.location.host,
hostname: window.location.hostname,
queryParams: queryParams,
protocol: window.location.protocol,
pathname: window.location.pathname,
port: window.location.port,
href: window.location.href,
hash: window.location.hash,
};
},
);
export const getUnevaluatedDataTree = createSelector(
getActionsForCurrentPage,
getWidgets,
getWidgetsMeta,
(actions, widgets, widgetsMeta) => {
return DataTreeFactory.create({ actions, widgets, widgetsMeta });
getUrlParams,
(actions, widgets, widgetsMeta, url) => {
return DataTreeFactory.create({
actions,
widgets,
widgetsMeta,
url,
});
},
);

View File

@ -13798,6 +13798,11 @@ url-parse@^1.4.3:
querystringify "^2.1.1"
requires-port "^1.0.0"
url-search-params-polyfill@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/url-search-params-polyfill/-/url-search-params-polyfill-8.0.0.tgz#17415ca6815ff0661e07737b84bcc28e708a7875"
integrity sha512-X4BTaEq1UMz9bTbMKQ6r+CippkKBsFWHiP9wycQc7aHH2Ml/Iieuo44+GJDb77pfP71bONYA/nUd4iokYAxVRQ==
url@0.11.0, url@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"