wrapping action code issue fixed. tree component is changed.

This commit is contained in:
vicky_primathon.in 2020-06-19 13:00:11 +05:30
parent f1bc994888
commit e950a3f935
3 changed files with 319 additions and 310 deletions

View File

@ -152,9 +152,6 @@ type SelectorViewProps = ViewProps & {
options: TreeDropdownOption[]; options: TreeDropdownOption[];
defaultText: string; defaultText: string;
getDefaults?: Function; getDefaults?: Function;
level: number;
levelSeparator?: string;
start: boolean;
displayValue?: string; displayValue?: string;
selectedLabelModifier?: ( selectedLabelModifier?: (
option: TreeDropdownOption, option: TreeDropdownOption,
@ -166,16 +163,13 @@ type KeyValueViewProps = ViewProps;
type TextViewProps = ViewProps & { type TextViewProps = ViewProps & {
isValid: boolean; isValid: boolean;
validationMessage?: string; validationMessage?: string;
level: number;
start: boolean;
levelSeparator?: string;
}; };
const views = { const views = {
[ViewTypes.SELECTOR_VIEW]: function SelectorView(props: SelectorViewProps) { [ViewTypes.SELECTOR_VIEW]: function SelectorView(props: SelectorViewProps) {
return ( return (
<FieldWrapper> <FieldWrapper>
<ControlWrapper key={props.label} level={props.level}> <ControlWrapper key={props.label} isAction={true}>
{props.label && <label>{props.label}</label>} {props.label && <label>{props.label}</label>}
<TreeDropdown <TreeDropdown
optionTree={props.options} optionTree={props.options}
@ -189,18 +183,12 @@ const views = {
displayValue={props.displayValue} displayValue={props.displayValue}
/> />
</ControlWrapper> </ControlWrapper>
<TreeStructure
level={props.level}
label={props.label}
start={props.start}
levelSeparator={props.levelSeparator}
/>
</FieldWrapper> </FieldWrapper>
); );
}, },
[ViewTypes.KEY_VALUE_VIEW]: function KeyValueView(props: KeyValueViewProps) { [ViewTypes.KEY_VALUE_VIEW]: function KeyValueView(props: KeyValueViewProps) {
return ( return (
<ControlWrapper key={props.label}> <ControlWrapper key={props.label} isAction={true}>
<KeyValueComponent <KeyValueComponent
pairs={props.get(props.value, false) as DropdownOption[]} pairs={props.get(props.value, false) as DropdownOption[]}
addLabel={"QueryParam"} addLabel={"QueryParam"}
@ -212,7 +200,7 @@ const views = {
[ViewTypes.TEXT_VIEW]: function TextView(props: TextViewProps) { [ViewTypes.TEXT_VIEW]: function TextView(props: TextViewProps) {
return ( return (
<FieldWrapper> <FieldWrapper>
<ControlWrapper key={props.label} level={props.level}> <ControlWrapper key={props.label} isAction={true}>
{props.label && <label>{props.label}</label>} {props.label && <label>{props.label}</label>}
<InputText <InputText
label={props.label} label={props.label}
@ -230,12 +218,6 @@ const views = {
errorMessage={props.validationMessage} errorMessage={props.validationMessage}
/> />
</ControlWrapper> </ControlWrapper>
<TreeStructure
level={props.level}
label={props.label}
start={props.start}
levelSeparator={props.levelSeparator}
/>
</FieldWrapper> </FieldWrapper>
); );
}, },
@ -419,9 +401,6 @@ function getOptionsWithChildren(
function getFieldFromValue( function getFieldFromValue(
value: string | undefined, value: string | undefined,
level: number,
start: boolean,
levelSeparator?: string,
getParentValue?: Function, getParentValue?: Function,
): any[] { ): any[] {
const fields: any[] = [ const fields: any[] = [
@ -429,9 +408,6 @@ function getFieldFromValue(
field: FieldType.ACTION_SELECTOR_FIELD, field: FieldType.ACTION_SELECTOR_FIELD,
getParentValue, getParentValue,
value, value,
level,
start,
levelSeparator,
}, },
]; ];
if (!value) { if (!value) {
@ -450,9 +426,6 @@ function getFieldFromValue(
} }
const successFields = getFieldFromValue( const successFields = getFieldFromValue(
`{{${sucesssValue}}}`, `{{${sucesssValue}}}`,
level + 1,
start,
"odd",
(changeValue: string) => { (changeValue: string) => {
const matches = [...value.matchAll(ACTION_TRIGGER_REGEX)]; const matches = [...value.matchAll(ACTION_TRIGGER_REGEX)];
const args = [...matches[0][2].matchAll(ACTION_ANONYMOUS_FUNC_REGEX)]; const args = [...matches[0][2].matchAll(ACTION_ANONYMOUS_FUNC_REGEX)];
@ -469,8 +442,6 @@ function getFieldFromValue(
}, },
); );
successFields[0].label = "onSuccess"; successFields[0].label = "onSuccess";
successFields[0].level = level + 1;
successFields[0].start = true;
fields.push(successFields); fields.push(successFields);
let errorValue; let errorValue;
@ -479,9 +450,6 @@ function getFieldFromValue(
} }
const errorFields = getFieldFromValue( const errorFields = getFieldFromValue(
`{{${errorValue}}}`, `{{${errorValue}}}`,
level + 1,
start,
"even",
(changeValue: string) => { (changeValue: string) => {
const matches = [...value.matchAll(ACTION_TRIGGER_REGEX)]; const matches = [...value.matchAll(ACTION_TRIGGER_REGEX)];
const args = [...matches[0][2].matchAll(ACTION_ANONYMOUS_FUNC_REGEX)]; const args = [...matches[0][2].matchAll(ACTION_ANONYMOUS_FUNC_REGEX)];
@ -497,51 +465,33 @@ function getFieldFromValue(
}, },
); );
errorFields[0].label = "onError"; errorFields[0].label = "onError";
errorFields[0].level = level + 1;
errorFields[0].start = false;
fields.push(errorFields); fields.push(errorFields);
} }
return fields; return fields;
} }
if (value.indexOf("navigateTo") !== -1) { if (value.indexOf("navigateTo") !== -1) {
fields.push({ fields.push({
field: FieldType.URL_FIELD, field: FieldType.URL_FIELD,
level: level + 1,
levelSeparator,
start: true,
}); });
} }
if (value.indexOf("showModal") !== -1) { if (value.indexOf("showModal") !== -1) {
fields.push({ fields.push({
field: FieldType.SHOW_MODAL_FIELD, field: FieldType.SHOW_MODAL_FIELD,
level: level + 1,
levelSeparator,
start: true,
}); });
} }
if (value.indexOf("closeModal") !== -1) { if (value.indexOf("closeModal") !== -1) {
fields.push({ fields.push({
field: FieldType.CLOSE_MODAL_FIELD, field: FieldType.CLOSE_MODAL_FIELD,
level: level + 1,
levelSeparator,
start: true,
}); });
} }
if (value.indexOf("showAlert") !== -1) { if (value.indexOf("showAlert") !== -1) {
fields.push( fields.push(
{ {
field: FieldType.ALERT_TEXT_FIELD, field: FieldType.ALERT_TEXT_FIELD,
level: level + 1,
levelSeparator,
start: true,
}, },
{ {
field: FieldType.ALERT_TYPE_SELECTOR_FIELD, field: FieldType.ALERT_TYPE_SELECTOR_FIELD,
level: level + 1,
levelSeparator,
start: false,
}, },
); );
} }
@ -556,6 +506,144 @@ function getPageDropdownOptions(state: AppState) {
})); }));
} }
function renderField(props: {
onValueChange: Function;
value: string;
field: any;
label?: string;
isValid: boolean;
validationMessage?: string;
apiOptionTree: TreeDropdownOption[];
queryOptionTree: TreeDropdownOption[];
modalDropdownList: TreeDropdownOption[];
pageDropdownOptions: TreeDropdownOption[];
depth: number;
maxDepth: number;
}) {
const { field } = props;
const fieldType = field.field;
const fieldConfig = fieldConfigs[fieldType];
const view = views[fieldConfig.view];
let viewElement: JSX.Element | null = null;
switch (fieldType) {
case FieldType.ACTION_SELECTOR_FIELD:
case FieldType.ON_SUCCESS_FIELD:
case FieldType.ON_ERROR_FIELD:
case FieldType.SHOW_MODAL_FIELD:
case FieldType.CLOSE_MODAL_FIELD:
case FieldType.PAGE_SELECTOR_FIELD:
case FieldType.ALERT_TYPE_SELECTOR_FIELD:
let label = "";
let defaultText = "Select Action";
let options = props.apiOptionTree;
let selectedLabelModifier = undefined;
let displayValue = undefined;
let getDefaults = undefined;
if (fieldType === FieldType.ACTION_SELECTOR_FIELD) {
label = props.label || "";
displayValue =
field.value !== "{{undefined}}" && field.value !== "{{()}}"
? field.value
: undefined;
// eslint-disable-next-line react/display-name
selectedLabelModifier = (
option: TreeDropdownOption,
displayValue?: string,
) => {
if (
option.type === ActionType.api ||
option.type === ActionType.query
) {
return <HightlightedCode codeText={`{{${option.label}.run()}}`} />;
} else if (displayValue) {
return <HightlightedCode codeText={displayValue} />;
}
return <span>{option.label}</span>;
};
getDefaults = (value: string) => {
return {
[ActionType.navigateTo]: `'${props.pageDropdownOptions[0].label}'`,
}[value];
};
}
if (
fieldType === FieldType.SHOW_MODAL_FIELD ||
fieldType === FieldType.CLOSE_MODAL_FIELD
) {
label = "Modal Name";
options = props.modalDropdownList;
defaultText = "Select Modal";
}
if (fieldType === FieldType.PAGE_SELECTOR_FIELD) {
label = "Page Name";
options = props.pageDropdownOptions;
defaultText = "Select Page";
}
if (fieldType === FieldType.ALERT_TYPE_SELECTOR_FIELD) {
label = "type";
options = ALERT_STYLE_OPTIONS;
defaultText = "Select type";
}
viewElement = (view as (props: SelectorViewProps) => JSX.Element)({
options: options,
label: label,
get: fieldConfig.getter,
set: (value: string | DropdownOption, defaultValue?: string) => {
const finalValueToSet = fieldConfig.setter(
value,
props.value,
defaultValue,
);
props.onValueChange(finalValueToSet);
},
value: props.value,
defaultText: defaultText,
getDefaults: getDefaults,
selectedLabelModifier: selectedLabelModifier,
displayValue: displayValue ? displayValue : "",
});
break;
case FieldType.KEY_VALUE_FIELD:
viewElement = (view as (props: SelectorViewProps) => JSX.Element)({
options: props.apiOptionTree,
label: "",
get: fieldConfig.getter,
set: (value: string | DropdownOption) => {
const finalValueToSet = fieldConfig.setter(value, props.value);
props.onValueChange(finalValueToSet);
},
value: props.value,
defaultText: "Select Action",
});
break;
case FieldType.ALERT_TEXT_FIELD:
case FieldType.URL_FIELD:
let fieldLabel = "";
if (fieldType === FieldType.ALERT_TEXT_FIELD) {
fieldLabel = "Message";
} else if (fieldType === FieldType.URL_FIELD) {
fieldLabel = "Page Name";
}
viewElement = (view as (props: TextViewProps) => JSX.Element)({
label: fieldLabel,
get: fieldConfig.getter,
set: (value: string | DropdownOption) => {
const finalValueToSet = fieldConfig.setter(value, props.value);
props.onValueChange(finalValueToSet);
},
value: props.value,
isValid: props.isValid,
validationMessage: props.validationMessage,
});
break;
default:
break;
}
return <div key={fieldType}>{viewElement}</div>;
}
function Fields(props: { function Fields(props: {
onValueChange: Function; onValueChange: Function;
value: string; value: string;
@ -570,171 +658,99 @@ function Fields(props: {
depth: number; depth: number;
maxDepth: number; maxDepth: number;
}) { }) {
const ui = props.fields.map((field: any, index: number) => { const { fields, ...otherProps } = props;
if (Array.isArray(field)) { if (fields[0].field === FieldType.ACTION_SELECTOR_FIELD) {
if (props.depth > props.maxDepth) { const remainingFields = fields.slice(1);
return null; return (
} <React.Fragment>
const selectorField = field[0]; {renderField({
console.log("selectorField", field[0], index); field: fields[0],
return ( ...otherProps,
<Fields })}
value={selectorField.value} <ul className={props.depth === 1 ? "tree" : ""}>
fields={field} {remainingFields.map((field: any, index: number) => {
label={selectorField.label} if (Array.isArray(field)) {
isValid={props.isValid} if (props.depth > props.maxDepth) {
validationMessage={props.validationMessage} return null;
apiOptionTree={props.apiOptionTree} }
queryOptionTree={props.queryOptionTree} const selectorField = field[0];
modalDropdownList={props.modalDropdownList}
pageDropdownOptions={props.pageDropdownOptions}
depth={props.depth + 1}
maxDepth={props.maxDepth}
onValueChange={(value: any) => {
props.onValueChange(
selectorField.getParentValue(
value.substring(2, value.length - 2),
),
);
}}
/>
);
}
const fieldType = field.field;
const fieldConfig = fieldConfigs[fieldType];
const view = views[fieldConfig.view];
let viewElement: JSX.Element | null = null;
switch (fieldType) {
case FieldType.ACTION_SELECTOR_FIELD:
case FieldType.ON_SUCCESS_FIELD:
case FieldType.ON_ERROR_FIELD:
case FieldType.SHOW_MODAL_FIELD:
case FieldType.CLOSE_MODAL_FIELD:
case FieldType.PAGE_SELECTOR_FIELD:
case FieldType.ALERT_TYPE_SELECTOR_FIELD:
let label = "";
let defaultText = "Select Action";
let options = props.apiOptionTree;
let selectedLabelModifier = undefined;
let displayValue = undefined;
let getDefaults = undefined;
if (fieldType === FieldType.ACTION_SELECTOR_FIELD) {
label = props.label || "";
displayValue =
field.value !== "{{undefined}}" && field.value !== "{{()}}"
? field.value
: undefined;
// eslint-disable-next-line react/display-name
selectedLabelModifier = (
option: TreeDropdownOption,
displayValue?: string,
) => {
if (
option.type === ActionType.api ||
option.type === ActionType.query
) {
return ( return (
<HightlightedCode codeText={`{{${option.label}.run()}}`} /> <li key={index}>
<Fields
value={selectorField.value}
fields={field}
label={selectorField.label}
isValid={props.isValid}
validationMessage={props.validationMessage}
apiOptionTree={props.apiOptionTree}
queryOptionTree={props.queryOptionTree}
modalDropdownList={props.modalDropdownList}
pageDropdownOptions={props.pageDropdownOptions}
depth={props.depth + 1}
maxDepth={props.maxDepth}
onValueChange={(value: any) => {
props.onValueChange(
selectorField.getParentValue(
value.substring(2, value.length - 2),
),
);
}}
/>
</li>
);
} else {
return (
<li>
{renderField({
field: field,
...otherProps,
})}
</li>
); );
} else if (displayValue) {
return <HightlightedCode codeText={displayValue} />;
} }
return <span>{option.label}</span>; })}
}; </ul>
getDefaults = (value: string) => { </React.Fragment>
return { );
[ActionType.navigateTo]: `'${props.pageDropdownOptions[0].label}'`, } else {
}[value]; const ui = fields.map((field: any, index: number) => {
}; if (Array.isArray(field)) {
if (props.depth > props.maxDepth) {
return null;
} }
if ( const selectorField = field[0];
fieldType === FieldType.SHOW_MODAL_FIELD || return (
fieldType === FieldType.CLOSE_MODAL_FIELD <Fields
) { key={index}
label = "Modal Name"; value={selectorField.value}
options = props.modalDropdownList; fields={field}
defaultText = "Select Modal"; label={selectorField.label}
} isValid={props.isValid}
if (fieldType === FieldType.PAGE_SELECTOR_FIELD) { validationMessage={props.validationMessage}
label = "Page Name"; apiOptionTree={props.apiOptionTree}
options = props.pageDropdownOptions; queryOptionTree={props.queryOptionTree}
defaultText = "Select Page"; modalDropdownList={props.modalDropdownList}
} pageDropdownOptions={props.pageDropdownOptions}
if (fieldType === FieldType.ALERT_TYPE_SELECTOR_FIELD) { depth={props.depth + 1}
label = "type"; maxDepth={props.maxDepth}
options = ALERT_STYLE_OPTIONS; onValueChange={(value: any) => {
defaultText = "Select type"; props.onValueChange(
} selectorField.getParentValue(
viewElement = (view as (props: SelectorViewProps) => JSX.Element)({ value.substring(2, value.length - 2),
options: options, ),
label: label, );
get: fieldConfig.getter, }}
set: (value: string | DropdownOption, defaultValue?: string) => { />
const finalValueToSet = fieldConfig.setter( );
value, } else {
props.value, return renderField({
defaultValue, field: field,
); ...otherProps,
props.onValueChange(finalValueToSet);
},
value: props.value,
defaultText: defaultText,
getDefaults: getDefaults,
selectedLabelModifier: selectedLabelModifier,
displayValue: displayValue ? displayValue : "",
level: field.level,
start: field.start,
levelSeparator: field.levelSeparator,
}); });
break; }
case FieldType.KEY_VALUE_FIELD: });
viewElement = (view as (props: SelectorViewProps) => JSX.Element)({ return <>{ui}</>;
options: props.apiOptionTree, }
label: "",
get: fieldConfig.getter,
set: (value: string | DropdownOption) => {
const finalValueToSet = fieldConfig.setter(value, props.value);
props.onValueChange(finalValueToSet);
},
value: props.value,
defaultText: "Select Action",
level: field.level,
start: field.start,
levelSeparator: field.levelSeparator,
});
break;
case FieldType.ALERT_TEXT_FIELD:
case FieldType.URL_FIELD:
let fieldLabel = "";
if (fieldType === FieldType.ALERT_TEXT_FIELD) {
fieldLabel = "Message";
} else if (fieldType === FieldType.URL_FIELD) {
fieldLabel = "Page Name";
}
viewElement = (view as (props: TextViewProps) => JSX.Element)({
label: fieldLabel,
get: fieldConfig.getter,
set: (value: string | DropdownOption) => {
const finalValueToSet = fieldConfig.setter(value, props.value);
props.onValueChange(finalValueToSet);
},
value: props.value,
isValid: props.isValid,
validationMessage: props.validationMessage,
level: field.level,
start: field.start,
levelSeparator: field.levelSeparator,
});
break;
default:
break;
}
return <div key={fieldType}>{viewElement}</div>;
});
return <>{ui}</>;
} }
function useModalDropdownList() { function useModalDropdownList() {
@ -843,21 +859,22 @@ export function ActionCreator(props: ActionCreatorProps) {
const queryOptionTree = useQueryOptionTree(); const queryOptionTree = useQueryOptionTree();
const modalDropdownList = useModalDropdownList(); const modalDropdownList = useModalDropdownList();
const pageDropdownOptions = useSelector(getPageDropdownOptions); const pageDropdownOptions = useSelector(getPageDropdownOptions);
const fields = getFieldFromValue(props.value, 0, false); const fields = getFieldFromValue(props.value);
console.log("fields", fields);
return ( return (
<Fields <TreeStructure>
value={props.value} <Fields
fields={fields} value={props.value}
isValid={props.isValid} fields={fields}
validationMessage={props.validationMessage} isValid={props.isValid}
apiOptionTree={apiOptionTree} validationMessage={props.validationMessage}
queryOptionTree={queryOptionTree} apiOptionTree={apiOptionTree}
modalDropdownList={modalDropdownList} queryOptionTree={queryOptionTree}
pageDropdownOptions={pageDropdownOptions} modalDropdownList={modalDropdownList}
onValueChange={props.onValueChange} pageDropdownOptions={pageDropdownOptions}
depth={1} onValueChange={props.onValueChange}
maxDepth={1} depth={1}
/> maxDepth={1}
/>
</TreeStructure>
); );
} }

View File

@ -17,7 +17,7 @@ import { Skin } from "constants/DefaultTheme";
type ControlWrapperProps = { type ControlWrapperProps = {
orientation?: ContainerOrientation; orientation?: ContainerOrientation;
level?: number; isAction?: boolean;
}; };
export const ControlWrapper = styled.div<ControlWrapperProps>` export const ControlWrapper = styled.div<ControlWrapperProps>`
@ -26,8 +26,7 @@ export const ControlWrapper = styled.div<ControlWrapperProps>`
align-items: center; align-items: center;
flex-direction: ${props => flex-direction: ${props =>
props.orientation === "VERTICAL" ? "column" : "row"}; props.orientation === "VERTICAL" ? "column" : "row"};
padding: ${props => props.theme.spaces[3]}px 0; padding: ${props => (props.isAction ? "0" : "8px 0 ")};
padding-left: ${props => (props.level ? 18 * props.level : 0)}px;
& > label { & > label {
color: ${props => props.theme.colors.paneText}; color: ${props => props.theme.colors.paneText};
margin-bottom: ${props => props.theme.spaces[1]}px; margin-bottom: ${props => props.theme.spaces[1]}px;
@ -81,6 +80,16 @@ export const StyledDropDownContainer = styled.div`
border: none; border: none;
box-shadow: none; box-shadow: none;
background: transparent; background: transparent;
white-space: normal;
word-break: break-word;
}
.bp3-button-text {
white-space: normal;
word-break: break-word;
display: block;
overflow: auto;
}
.bp3-icon {
} }
} }
} }

View File

@ -1,89 +1,72 @@
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
const TreeStructureWrapper = styled.div`
li {
list-style: none;
}
.tree,
.tree ul {
margin-bottom: 0;
margin-top: 0;
margin-left: 9px;
padding: 0;
list-style: none;
color: ${props => props.theme.colors.paneText};
position: relative;
}
.tree ul {
margin-left: 9px;
}
.tree:before,
.tree ul:before {
content: "";
display: block;
width: 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
border-left: 2px solid;
}
.tree li {
margin: 0;
padding-left: 9px;
line-height: 18px;
padding-top: 16px;
position: relative;
}
.tree li:before {
content: "";
display: block;
width: 9px;
height: 0;
border-top: 2px solid;
margin-top: 36px;
position: absolute;
top: 18px;
left: 0;
}
.tree li:last-child:before {
background: ${props => props.theme.colors.paneBG};
height: auto;
top: 18px;
bottom: 0;
}
`;
type TreeStructureProps = { type TreeStructureProps = {
label: string; children: React.ReactNode;
level: number;
start: boolean;
levelSeparator?: string;
}; };
const TreeStructureHorizontalWrapper = styled.div<{
level: number;
label: string;
}>`
position: absolute;
width: ${props => (props.level - 1) * 2 + 9}px;
height: 2px;
background: #a2a6a8;
top: ${props => (props.label ? "65%" : "50%")};
left: ${props => (props.level - 1) * 18 + 9}px;
z-index: 1;
`;
const TreeStructureVerticalWrapper = styled.div<{
level: number;
label: string;
start: boolean;
}>`
position: absolute;
height: ${props => (props.start ? (props.label ? "77%" : "70%") : "100%")};
width: 2px;
background: #a2a6a8;
top: ${props =>
props.start
? props.label
? "-12%"
: "-16%"
: props.label
? "-35%"
: "-49%"};
left: ${props => (props.level - 1) * 18 + 9}px;
z-index: 1;
`;
const TreeStructure = (props: TreeStructureProps) => { const TreeStructure = (props: TreeStructureProps) => {
return ( return <TreeStructureWrapper>{props.children}</TreeStructureWrapper>;
<React.Fragment>
{props.level ? (
<TreeStructureHorizontalWrapper
label={props.label}
level={props.level}
/>
) : null}
{(() => {
if (
props.level &&
props.levelSeparator &&
props.levelSeparator === "odd"
) {
const treeStructureVerticalWrappers = new Array(props.level)
.fill("")
.map((i, index) => {
return (
<TreeStructureVerticalWrapper
key={index}
label={props.label}
level={index + 1}
start={index === props.level - 1 ? props.start : false}
/>
);
});
return treeStructureVerticalWrappers;
} else if (props.level) {
return (
<TreeStructureVerticalWrapper
label={props.label}
level={props.level}
start={props.start}
/>
);
} else {
return [];
}
})()}
</React.Fragment>
);
}; };
export default TreeStructure; export default TreeStructure;