Feature/intercom (#521)

* removed duplicate user object
removed id field which is never populated
added help modal in applications page and intercom to load in help modal
shutdown intercom on signout to clear existing chats

* added analytics to help modal and invite user
unescaped bindings before evaluation to prune newlines

* updated action confirmation text

* added a check to ignore old properties which are no longer dynamic

* fixed test case

* fix tests

Co-authored-by: Nikhil Nandagopal <nikhil@appsmith.com>
Co-authored-by: Hetu Nandu <hetunandu@gmail.com>
This commit is contained in:
Nikhil Nandagopal 2020-09-10 12:56:55 +05:30 committed by GitHub
parent 02c3c199ac
commit 7724fe5d82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 41 additions and 17 deletions

View File

@ -28,7 +28,8 @@ describe("Confirm run action", function() {
cy.get(queryEditor.runQuery).click();
cy.get(".bp3-dialog")
.contains("Confirm and run")
.find(".bp3-button")
.contains("Confirm")
.click();
cy.wait("@postExecute").should(
"have.nested.property",

View File

@ -15,6 +15,7 @@ import { connect } from "react-redux";
import { AppState } from "reducers";
import { getCurrentUser } from "selectors/usersSelectors";
import { User } from "constants/userConstants";
import AnalyticsUtil from "utils/AnalyticsUtil";
const { algolia, cloudHosting, intercomAppID } = getAppsmithConfigs();
const HelpButton = styled.button<{
@ -57,6 +58,7 @@ type Props = {
isHelpModalOpen: boolean;
dispatch: any;
user?: User;
page: string;
};
class HelpModal extends React.Component<Props> {
@ -111,6 +113,7 @@ class HelpModal extends React.Component<Props> {
highlight={!isHelpModalOpen}
layer={layers.help}
onClick={() => {
AnalyticsUtil.logEvent("OPEN_HELP", { page: this.props.page });
dispatch(setHelpModalVisibility(!isHelpModalOpen));
}}
>

View File

@ -338,7 +338,7 @@ class Applications extends Component<
</OrgSection>
);
})}
<HelpModal />
<HelpModal page={"Applications"} />
</PageWrapper>
);
}

View File

@ -24,9 +24,9 @@ class ConfirmRunModal extends React.Component<Props> {
};
return (
<Dialog title="Confirm run" isOpen={isModalOpen} onClose={handleClose}>
<Dialog title="Confirm Action" isOpen={isModalOpen} onClose={handleClose}>
<div className={Classes.DIALOG_BODY}>
Are you sure you want to refresh your current data
Are you sure you want to perform this action?
</div>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
@ -41,7 +41,7 @@ class ConfirmRunModal extends React.Component<Props> {
/>
<Button
filled
text="Confirm and run"
text="Confirm"
intent="primary"
onClick={() => {
dispatch(acceptRunActionConfirmModal());

View File

@ -257,7 +257,7 @@ export const EditorHeader = (props: EditorHeaderProps) => {
/>
</DeploySection>
</HeaderSection>
<HelpModal />
<HelpModal page={"Editor"} />
</HeaderWrapper>
);
};

View File

@ -34,6 +34,7 @@ import {
} from "../Applications/permissionHelpers";
import { getAppsmithConfigs } from "configs";
import { ReactComponent as NoEmailConfigImage } from "assets/images/email-not-configured.svg";
import AnalyticsUtil from "utils/AnalyticsUtil";
const OrgInviteTitle = styled.div`
font-weight: bold;
@ -228,6 +229,7 @@ const OrgInviteUsersForm = (props: any) => {
<StyledForm
onSubmit={handleSubmit((values: any, dispatch: any) => {
validateFormValues(values);
AnalyticsUtil.logEvent("INVITE_USER", values);
return inviteUsersToOrg({ ...values, orgId: props.orgId }, dispatch);
})}
>

View File

@ -64,6 +64,8 @@ export type EventName =
| "PROPERTY_PANE_OPEN"
| "PROPERTY_PANE_CLOSE"
| "PROPERTY_PANE_OPEN_CLICK"
| "OPEN_HELP"
| "INVITE_USER"
| "PROPERTY_PANE_CLOSE_CLICK";
function getApplicationId(location: Location) {

View File

@ -123,12 +123,7 @@ export const evaluateDynamicBoundValue = (
path: string,
callbackData?: any,
): JSExecutorResult => {
const unescapedInput = unescapeJS(path);
return JSExecutionManagerSingleton.evaluateSync(
unescapedInput,
data,
callbackData,
);
return JSExecutionManagerSingleton.evaluateSync(path, data, callbackData);
};
// For creating a final value where bindings could be in a template format
@ -265,6 +260,8 @@ export function getEvaluatedDataTree(dataTree: DataTree): DataTree {
// Create Dependencies DAG
const createDepsStart = performance.now();
const dataTreeString = JSON.stringify(dataTree);
// Stringify before doing a fast equals because the data tree has functions and fast equal will always treat those as changed values
// Better solve will be to prune functions
if (!equal(dataTreeString, cachedDataTreeString)) {
cachedDataTreeString = dataTreeString;
dependencyTreeCache = createDependencyTree(dataTree);
@ -333,10 +330,20 @@ export const createDependencyTree = (
];
});
if (entity.dynamicBindings) {
Object.keys(entity.dynamicBindings).forEach(prop => {
const { jsSnippets } = getDynamicBindings(_.get(entity, prop));
const existingDeps = dependencyMap[`${entityKey}.${prop}`] || [];
dependencyMap[`${entityKey}.${prop}`] = existingDeps.concat(
Object.keys(entity.dynamicBindings).forEach(propertyName => {
// using unescape to remove new lines from bindings which interfere with our regex extraction
let unevalPropValue = _.get(entity, propertyName);
if (
_.isString(unevalPropValue) &&
isDynamicValue(unevalPropValue)
) {
unevalPropValue = unescapeJS(unevalPropValue);
}
_.set(entity, propertyName, unevalPropValue);
const { jsSnippets } = getDynamicBindings(unevalPropValue);
const existingDeps =
dependencyMap[`${entityKey}.${propertyName}`] || [];
dependencyMap[`${entityKey}.${propertyName}`] = existingDeps.concat(
jsSnippets.filter(jsSnippet => !!jsSnippet),
);
});
@ -350,7 +357,16 @@ export const createDependencyTree = (
if (entity.ENTITY_TYPE === ENTITY_TYPE.ACTION) {
if (entity.dynamicBindingPathList.length) {
entity.dynamicBindingPathList.forEach(prop => {
const { jsSnippets } = getDynamicBindings(_.get(entity, prop.key));
// using unescape to remove new lines from bindings which interfere with our regex extraction
let unevalPropValue = _.get(entity, prop.key);
if (
_.isString(unevalPropValue) &&
isDynamicValue(unevalPropValue)
) {
unevalPropValue = unescapeJS(unevalPropValue);
}
_.set(entity, prop.key, unevalPropValue);
const { jsSnippets } = getDynamicBindings(unevalPropValue);
const existingDeps =
dependencyMap[`${entityKey}.${prop.key}`] || [];
dependencyMap[`${entityKey}.${prop.key}`] = existingDeps.concat(