Fix for slash commands blocker issues

(cherry picked from commit 6c0da9a380)
This commit is contained in:
arunvjn 2021-07-15 20:08:31 +05:30 committed by arunvjn
parent ccf017be12
commit c2ecfa94b3
12 changed files with 81 additions and 73 deletions

View File

@ -0,0 +1,4 @@
<svg width="9" height="12" viewBox="0 0 9 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.79102 11.1094H4.11328V10.2832H3.87891C3.05273 10.2832 2.71875 9.90234 2.71875 8.96484V7.07812C2.71875 6.23438 2.29688 5.79492 1.43555 5.70703V5.56641C2.29688 5.47852 2.71875 5.03906 2.71875 4.19531V2.32031C2.71875 1.38281 3.05273 1.00195 3.87891 1.00195H4.11328V0.175781H3.79102C2.4082 0.175781 1.75781 0.826172 1.75781 2.19141V3.83203C1.75781 4.76953 1.43555 5.08008 0.46875 5.08008V6.19336C1.43555 6.19336 1.75781 6.50391 1.75781 7.44141V9.09375C1.75781 10.459 2.4082 11.1094 3.79102 11.1094Z" fill="#4B4848"/>
<path d="M8.13305 11.1094H8.45531V10.2832H8.22094C7.39477 10.2832 7.06078 9.90234 7.06078 8.96484V7.07812C7.06078 6.23438 6.63891 5.79492 5.77758 5.70703V5.56641C6.63891 5.47852 7.06078 5.03906 7.06078 4.19531V2.32031C7.06078 1.38281 7.39477 1.00195 8.22094 1.00195H8.45531V0.175781H8.13305C6.75023 0.175781 6.09984 0.826172 6.09984 2.19141V3.83203C6.09984 4.76953 5.77758 5.08008 4.81078 5.08008V6.19336C5.77758 6.19336 6.09984 6.50391 6.09984 7.44141V9.09375C6.09984 10.459 6.75023 11.1094 8.13305 11.1094Z" fill="#4B4848"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,3 @@
<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.38281 11.8271C6.71777 11.8271 6.99805 11.5605 6.99805 11.2324V6.68652H11.4141C11.7422 6.68652 12.0225 6.40625 12.0225 6.07129C12.0225 5.73633 11.7422 5.46289 11.4141 5.46289H6.99805V0.910156C6.99805 0.582031 6.71777 0.31543 6.38281 0.31543C6.04785 0.31543 5.77441 0.582031 5.77441 0.910156V5.46289H1.35156C1.02344 5.46289 0.743164 5.73633 0.743164 6.07129C0.743164 6.40625 1.02344 6.68652 1.35156 6.68652H5.77441V11.2324C5.77441 11.5605 6.04785 11.8271 6.38281 11.8271Z" fill="#4B4848"/>
</svg>

After

Width:  |  Height:  |  Size: 603 B

View File

@ -6,6 +6,7 @@ import { generateQuickCommands } from "./generateQuickCommands";
import { Datasource } from "entities/Datasource";
import AnalyticsUtil from "utils/AnalyticsUtil";
import log from "loglevel";
import { ENTITY_TYPE } from "entities/AppsmithConsole";
export const commandsHelper: HintHelper = (editor, data: any) => {
let entitiesForSuggestions = Object.values(data).filter(
@ -19,21 +20,15 @@ export const commandsHelper: HintHelper = (editor, data: any) => {
{
datasources,
executeCommand,
mutedHinting,
pluginIdToImageLocation,
recentEntities,
updatePropertyValue,
update,
}: {
mutedHinting?: boolean;
datasources: Datasource[];
executeCommand: (payload: { actionType: string; args?: any }) => void;
pluginIdToImageLocation: Record<string, string>;
recentEntities: string[];
updatePropertyValue: (
value: string,
cursor?: number,
preventAutoComplete?: boolean,
) => void;
update: (value: string) => void;
},
): boolean => {
const currentEntityType = data[entityName]?.ENTITY_TYPE || "ACTION";
@ -45,7 +40,8 @@ export const commandsHelper: HintHelper = (editor, data: any) => {
const cursorBetweenBinding = checkIfCursorInsideBinding(editor);
const value = editor.getValue();
const slashIndex = value.lastIndexOf("/");
const shouldShowBinding = (!value && !mutedHinting) || slashIndex > -1;
const shouldShowBinding =
slashIndex > -1 || (!value && currentEntityType === ENTITY_TYPE.WIDGET);
if (!cursorBetweenBinding && shouldShowBinding) {
const searchText = value.substring(slashIndex + 1);
const list = generateQuickCommands(
@ -81,16 +77,19 @@ export const commandsHelper: HintHelper = (editor, data: any) => {
selectedHint: 1,
};
CodeMirror.on(hints, "pick", (selected: CommandsCompletion) => {
const updatedValue = value.slice(
0,
value.length - searchText.length - 1,
);
if (selected.action && typeof selected.action === "function") {
updatePropertyValue(updatedValue, updatedValue.length, true);
selected.action();
} else {
updatePropertyValue(updatedValue + selected.text);
}
update(value.slice(0, slashIndex) + selected.text);
setTimeout(() => {
editor.focus();
editor.setCursor({
line: editor.lineCount() - 1,
ch: editor.getLine(editor.lineCount() - 1).length - 2,
});
if (selected.action && typeof selected.action === "function") {
selected.action();
} else {
CodeMirror.signal(editor, "postPick");
}
});
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { data, render, ...rest } = selected;

View File

@ -6,7 +6,13 @@ import sortBy from "lodash/sortBy";
import { PluginType } from "entities/Action";
import { ReactComponent as ApisIcon } from "assets/icons/menu/api-colored.svg";
import { ReactComponent as DataSourcesColoredIcon } from "assets/icons/menu/datasource-colored.svg";
import { ReactComponent as NewPlus } from "assets/icons/menu/new-plus.svg";
import { ReactComponent as Binding } from "assets/icons/menu/binding.svg";
enum Shortcuts {
PLUS = "PLUS",
BINDING = "BINDING",
}
export const generateQuickCommands = (
entitiesForSuggestions: any[],
currentEntityType: string,
@ -25,19 +31,20 @@ export const generateQuickCommands = (
) => {
const suggestionsHeader: CommandsCompletion = commandsHeader("Bind Data");
const createNewHeader: CommandsCompletion = commandsHeader("Create New");
recentEntities.reverse();
const newBinding: CommandsCompletion = generateCreateNewCommand({
text: "{{}}",
displayText: "New Binding",
shortcut: "{{}}",
shortcut: Shortcuts.BINDING,
});
const newDatasource: CommandsCompletion = generateCreateNewCommand({
const newIntegration: CommandsCompletion = generateCreateNewCommand({
text: "",
displayText: "New Datasource",
action: () =>
executeCommand({
actionType: "NEW_DATASOURCE",
actionType: "NEW_INTEGRATION",
}),
shortcut: "datasource.new",
shortcut: Shortcuts.PLUS,
});
const suggestions = entitiesForSuggestions.map((suggestion: any) => {
const name = suggestion.name || suggestion.widgetName;
@ -45,7 +52,6 @@ export const generateQuickCommands = (
text: currentEntityType === "WIDGET" ? `{{${name}.data}}` : `{{${name}}}`,
displayText: `${name}`,
className: "CodeMirror-commands",
shortcut: "{{}}",
data: suggestion,
render: (element: HTMLElement, self: any, data: any) => {
const pluginType = data.data.pluginType as PluginType;
@ -65,7 +71,6 @@ export const generateQuickCommands = (
text: "",
displayText: `${action.name}`,
className: "CodeMirror-commands",
shortcut: `${action.name}.new`,
data: action,
action: () =>
executeCommand({
@ -88,7 +93,7 @@ export const generateQuickCommands = (
suggestions,
searchText,
recentEntities,
currentEntityType === "WIDGET" ? 2 : 3,
5,
);
suggestionsMatchingSearchText.push(
...matchingCommands([newBinding], searchText, []),
@ -105,7 +110,7 @@ export const generateQuickCommands = (
);
if (currentEntityType === "WIDGET") {
createNewCommandsMatchingSearchText.push(
...matchingCommands([newDatasource], searchText, []),
...matchingCommands([newIntegration], searchText, []),
);
}
let list: CommandsCompletion[] = [];
@ -123,13 +128,12 @@ const matchingCommands = (
list: any,
searchText: string,
recentEntities: string[] = [],
limit = 2,
limit = 5,
) => {
list = list.filter((action: any) => {
return (
action.displayText.toLowerCase().startsWith(searchText.toLowerCase()) ||
action.shortcut.toLowerCase().startsWith(searchText.toLowerCase())
);
return action.displayText
.toLowerCase()
.startsWith(searchText.toLowerCase());
});
list = sortBy(list, (a: any) => {
return (
@ -171,7 +175,11 @@ const generateCreateNewCommand = ({
action: action,
render: (element: HTMLElement, self: any, data: any) => {
ReactDOM.render(
<Command name={data.displayText} shortcut={data.shortcut} />,
<Command
customText={data.customText}
name={data.displayText}
shortcut={data.shortcut}
/>,
element,
);
},
@ -181,7 +189,8 @@ function Command(props: {
pluginType?: PluginType;
imgSrc?: string;
name: string;
shortcut: string;
shortcut: Shortcuts;
customText?: string;
}) {
return (
<div className="command-container">
@ -193,9 +202,12 @@ function Command(props: {
SAAS: <DataSourcesColoredIcon />,
}[props.pluginType]}
{props.imgSrc && <img src={props.imgSrc} />}
{props.shortcut &&
{ [Shortcuts.BINDING]: <Binding />, [Shortcuts.PLUS]: <NewPlus /> }[
props.shortcut
]}
<span>{props.name}</span>
</div>
<span className="shortcut">{props.shortcut}</span>
</div>
);
}

View File

@ -93,7 +93,6 @@ export type EditorStyleProps = {
disabled?: boolean;
link?: string;
showLightningMenu?: boolean;
mutedHinting?: boolean;
dataTreePath?: string;
evaluatedValue?: any;
expected?: string;
@ -227,6 +226,7 @@ class CodeEditor extends Component<Props, State> {
editor.on("cursorActivity", this.handleCursorMovement);
editor.on("focus", this.onFocusTrigger);
editor.on("blur", this.handleEditorBlur);
editor.on("postPick", () => this.handleAutocompleteVisibility(editor));
if (this.props.height) {
editor.setSize("100%", this.props.height);
} else {
@ -290,11 +290,9 @@ class CodeEditor extends Component<Props, State> {
showLightningMenu?: boolean,
additionalDynamicData?: Record<string, Record<string, unknown>>,
) {
return (showLightningMenu !== false ? hinting : [bindingHint]).map(
(helper) => {
return helper(editor, dynamicData, additionalDynamicData);
},
);
return hinting.map((helper) => {
return helper(editor, dynamicData, additionalDynamicData);
});
}
onFocusTrigger = (cm: CodeMirror.Editor) => {
@ -328,10 +326,12 @@ class CodeEditor extends Component<Props, State> {
handleEditorFocus = () => {
this.setState({ isFocused: true });
if (this.props.size === EditorSize.COMPACT) {
const inputValue = this.props.input.value;
this.editor.setOption("lineWrapping", true);
this.editor.setValue(inputValue);
this.editor.setCursor(inputValue.length);
this.editor.operation(() => {
const inputValue = this.props.input.value;
this.editor.setOption("lineWrapping", true);
this.editor.setValue(inputValue);
this.editor.setCursor(inputValue.length);
});
}
if (this.editor.getValue().length === 0)
this.handleAutocompleteVisibility(this.editor);
@ -339,12 +339,10 @@ class CodeEditor extends Component<Props, State> {
handleEditorBlur = () => {
this.handleChange();
// on blur closing the binding prompt for an editor regardless.
this.setState({ isFocused: false });
if (this.props.size === EditorSize.COMPACT) {
this.editor.setOption("lineWrapping", false);
}
this.editor.setOption("matchBrackets", false);
};
@ -375,7 +373,8 @@ class CodeEditor extends Component<Props, State> {
const inputValue = this.props.input.value || "";
if (
this.props.input.onChange &&
value !== inputValue &&
(value !== inputValue ||
_.get(this.editor, "state.completionActive.startLen") === 0) &&
this.state.isFocused
) {
this.props.input.onChange(value);
@ -383,7 +382,8 @@ class CodeEditor extends Component<Props, State> {
CodeEditor.updateMarkings(this.editor, this.props.marking);
};
handleAutocompleteVisibility = (cm: CodeMirror.Editor, force?: boolean) => {
handleAutocompleteVisibility = (cm: CodeMirror.Editor) => {
if (!this.state.isFocused) return;
const expected = this.props.expected ? this.props.expected : "";
const { entityName } = getEntityNameAndPropertyPath(
this.props.dataTreePath || "",
@ -391,17 +391,16 @@ class CodeEditor extends Component<Props, State> {
let hinterOpen = false;
for (let i = 0; i < this.hinters.length; i++) {
hinterOpen = this.hinters[i].showHint(cm, expected, entityName, {
mutedHinting: force ? !force : this.props.mutedHinting,
datasources: this.props.datasources.list,
pluginIdToImageLocation: this.props.pluginIdToImageLocation,
updatePropertyValue: this.updatePropertyValue.bind(this),
recentEntities: this.props.recentEntities,
update: this.props.input.onChange?.bind(this),
executeCommand: (payload: any) => {
this.props.executeCommand({
...payload,
callback: (binding: string) => {
const value = this.editor.getValue() + binding;
this.updatePropertyValue(value);
this.updatePropertyValue(value, value.length);
},
});
},
@ -432,20 +431,13 @@ class CodeEditor extends Component<Props, State> {
this.editor.setValue(value);
}
this.editor.focus();
if (cursor === undefined) {
if (value) {
cursor = value.length - 2;
} else {
cursor = 1;
}
}
this.editor.setCursor({
line: 0,
ch: cursor,
line: cursor || this.editor.lineCount() - 1,
ch: this.editor.getLine(this.editor.lineCount() - 1).length - 2,
});
this.setState({ isFocused: true }, () => {
if (preventAutoComplete) return;
this.handleAutocompleteVisibility(this.editor, true);
this.handleAutocompleteVisibility(this.editor);
});
}
@ -598,7 +590,10 @@ class CodeEditor extends Component<Props, State> {
)}
<BindingPrompt
editorTheme={this.props.theme}
isOpen={showBindingPrompt(showEvaluatedValue, input.value)}
isOpen={
showBindingPrompt(showEvaluatedValue, input.value) &&
!_.get(this.editor, "state.completionActive")
}
promptMessage={this.props.promptMessage}
showLightningMenu={this.props.showLightningMenu}
/>

View File

@ -136,7 +136,6 @@ function KeyValueRow(props: Props & WrappedFieldArrayProps) {
hoverInteraction
name={`${field}.key`}
placeholder={`Key ${index + 1}`}
showLightningMenu={false}
theme={props.theme}
/>
</Flex>
@ -149,7 +148,6 @@ function KeyValueRow(props: Props & WrappedFieldArrayProps) {
dataTreePath={`${props.dataTreePath}[${index}].value`}
expected={FIELD_VALUES.API_ACTION.params}
hoverInteraction
mutedHinting
name={`${field}.value`}
placeholder={`Value ${index + 1}`}
theme={props.theme}
@ -169,7 +167,6 @@ function KeyValueRow(props: Props & WrappedFieldArrayProps) {
)
}
expected={FIELD_VALUES.API_ACTION.params}
mutedHinting
name={`${field}.value`}
placeholder={
props.placeholder

View File

@ -65,7 +65,6 @@ class DynamicTextControl extends BaseControl<
configProperty,
evaluationSubstitutionType,
label,
mutedHinting,
placeholderText,
responseType,
} = this.props;
@ -105,7 +104,6 @@ class DynamicTextControl extends BaseControl<
dataTreePath={dataTreePath}
evaluationSubstitutionType={evaluationSubstitutionType}
mode={mode}
mutedHinting={mutedHinting}
name={this.props.configProperty}
placeholder={placeholderText}
size={EditorSize.EXTENDED}

View File

@ -52,6 +52,7 @@ export const CodemirrorHintStyles = createGlobalStyle<{
pointer-events: none !important;
font-family: ${(props) => props.theme.fonts.text};
${(props) => getTypographyByKey(props, "p3")}
font-weight: 600;
}
.CodeMirror-commands {
@ -86,6 +87,8 @@ export const CodemirrorHintStyles = createGlobalStyle<{
margin-right: 7px;
}
svg {
height: 12px;
width: 12px;
margin-right: 7px;
}
}

View File

@ -72,7 +72,6 @@ function PostBodyData(props: Props) {
dataTreePath={`${dataTreePath}.body`}
expected={FIELD_VALUES.API_ACTION.body}
mode={EditorModes.JSON_WITH_BINDING}
mutedHinting
name="actionConfiguration.body"
placeholder={
'{\n "name":"{{ inputName.property }}",\n "preference":"{{ dropdownName.property }}"\n}\n\n\\\\Take widget inputs using {{ }}'

View File

@ -183,14 +183,12 @@ function RapidApiEditorForm(props: Props) {
<DynamicTextField
disabled
leftImage={providerImage}
mutedHinting
name="provider.name"
placeholder="Provider name"
/>
<DynamicTextField
disabled
leftIcon={FormIcons.SLASH_ICON}
mutedHinting
name="actionConfiguration.path"
placeholder="v1/method"
/>

View File

@ -743,7 +743,7 @@ function* executeCommand(
const pageId = yield select(getCurrentPageId);
const applicationId = yield select(getCurrentApplicationId);
switch (actionPayload.payload.actionType) {
case "NEW_DATASOURCE":
case "NEW_INTEGRATION":
history.push(
INTEGRATION_EDITOR_URL(applicationId, pageId, INTEGRATION_TABS.NEW),
);

View File

@ -76,7 +76,7 @@ class FormControlRegistry {
});
FormControlFactory.registerControlBuilder("QUERY_DYNAMIC_TEXT", {
buildPropertyControl(controlProps: DynamicTextFieldProps): JSX.Element {
return <DynamicTextControl {...controlProps} mutedHinting />;
return <DynamicTextControl {...controlProps} />;
},
});
FormControlFactory.registerControlBuilder("QUERY_DYNAMIC_INPUT_TEXT", {