Update debugger error message CTA's (#6416)
This commit is contained in:
parent
f05e32a97e
commit
8e08e778d4
|
|
@ -1,5 +1,5 @@
|
|||
import { ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
import { Message, ENTITY_TYPE } from "entities/AppsmithConsole";
|
||||
import { ENTITY_TYPE, Log, Message } from "entities/AppsmithConsole";
|
||||
import { EventName } from "utils/AnalyticsUtil";
|
||||
|
||||
export interface LogDebuggerErrorAnalyticsPayload {
|
||||
|
|
@ -8,15 +8,18 @@ export interface LogDebuggerErrorAnalyticsPayload {
|
|||
entityType: ENTITY_TYPE;
|
||||
eventName: EventName;
|
||||
propertyPath: string;
|
||||
errorMessages: { message: string }[];
|
||||
errorMessages?: Message[];
|
||||
errorMessage?: Message["message"];
|
||||
errorType?: Message["type"];
|
||||
analytics?: Log["analytics"];
|
||||
}
|
||||
|
||||
export const debuggerLogInit = (payload: Message) => ({
|
||||
export const debuggerLogInit = (payload: Log) => ({
|
||||
type: ReduxActionTypes.DEBUGGER_LOG_INIT,
|
||||
payload,
|
||||
});
|
||||
|
||||
export const debuggerLog = (payload: Message) => ({
|
||||
export const debuggerLog = (payload: Log) => ({
|
||||
type: ReduxActionTypes.DEBUGGER_LOG,
|
||||
payload,
|
||||
});
|
||||
|
|
@ -30,16 +33,33 @@ export const showDebugger = (payload?: boolean) => ({
|
|||
payload,
|
||||
});
|
||||
|
||||
export const errorLog = (payload: Message) => ({
|
||||
type: ReduxActionTypes.DEBUGGER_ERROR_LOG,
|
||||
// Add an error
|
||||
export const addErrorLogInit = (payload: Log) => ({
|
||||
type: ReduxActionTypes.DEBUGGER_ADD_ERROR_LOG_INIT,
|
||||
payload,
|
||||
});
|
||||
|
||||
export const updateErrorLog = (payload: Message) => ({
|
||||
type: ReduxActionTypes.DEBUGGER_UPDATE_ERROR_LOG,
|
||||
export const addErrorLog = (payload: Log) => ({
|
||||
type: ReduxActionTypes.DEBUGGER_ADD_ERROR_LOG,
|
||||
payload,
|
||||
});
|
||||
|
||||
export const deleteErrorLogInit = (
|
||||
id: string,
|
||||
analytics?: Log["analytics"],
|
||||
) => ({
|
||||
type: ReduxActionTypes.DEBUGGER_DELETE_ERROR_LOG_INIT,
|
||||
payload: {
|
||||
id,
|
||||
analytics,
|
||||
},
|
||||
});
|
||||
|
||||
export const deleteErrorLog = (id: string) => ({
|
||||
type: ReduxActionTypes.DEBUGGER_DELETE_ERROR_LOG,
|
||||
payload: id,
|
||||
});
|
||||
|
||||
// Only used for analytics
|
||||
export const logDebuggerErrorAnalytics = (
|
||||
payload: LogDebuggerErrorAnalyticsPayload,
|
||||
|
|
|
|||
|
|
@ -341,17 +341,6 @@ if (intercomAppID) {
|
|||
});
|
||||
}
|
||||
|
||||
export function bootIntercom(intercomAppID: string, user?: User) {
|
||||
if (intercomAppID && window.Intercom) {
|
||||
window.Intercom("boot", {
|
||||
app_id: intercomAppID,
|
||||
user_id: user?.username,
|
||||
name: user?.name,
|
||||
email: user?.email,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class DocumentationSearch extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import React, { SyntheticEvent } from "react";
|
||||
import DocumentationSearch, {
|
||||
bootIntercom,
|
||||
} from "components/designSystems/appsmith/help/DocumentationSearch";
|
||||
import DocumentationSearch from "components/designSystems/appsmith/help/DocumentationSearch";
|
||||
import { getHelpModalOpen } from "selectors/helpSelectors";
|
||||
import {
|
||||
setHelpDefaultRefinement,
|
||||
|
|
@ -19,7 +17,7 @@ import AnalyticsUtil from "utils/AnalyticsUtil";
|
|||
import { HELP_MODAL_HEIGHT, HELP_MODAL_WIDTH } from "constants/HelpConstants";
|
||||
import { getCurrentUser } from "selectors/usersSelectors";
|
||||
import { User } from "constants/userConstants";
|
||||
const { intercomAppID } = getAppsmithConfigs();
|
||||
import { bootIntercom } from "utils/helpers";
|
||||
|
||||
const { algolia } = getAppsmithConfigs();
|
||||
const HelpButton = styled.button<{
|
||||
|
|
@ -70,12 +68,12 @@ class HelpModal extends React.Component<Props> {
|
|||
static contextType = LayersContext;
|
||||
componentDidMount() {
|
||||
const { user } = this.props;
|
||||
bootIntercom(intercomAppID, user);
|
||||
bootIntercom(user);
|
||||
}
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
const { user } = this.props;
|
||||
if (user?.email && prevProps.user?.email !== user?.email) {
|
||||
bootIntercom(intercomAppID, user);
|
||||
bootIntercom(user);
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ import { BlankState } from "./helpers";
|
|||
import LogItem, { getLogItemProps } from "./LogItem";
|
||||
import { usePagination, useFilteredLogs } from "./hooks";
|
||||
import { createMessage, NO_LOGS } from "constants/messages";
|
||||
import { useSelector } from "react-redux";
|
||||
import { getCurrentUser } from "selectors/usersSelectors";
|
||||
import { bootIntercom } from "utils/helpers";
|
||||
|
||||
const LIST_HEADER_HEIGHT = "38px";
|
||||
|
||||
|
|
@ -45,6 +48,11 @@ function DebbuggerLogs(props: Props) {
|
|||
() => LOGS_FILTER_OPTIONS.find((option) => option.value === filter),
|
||||
[filter],
|
||||
);
|
||||
const currentUser = useSelector(getCurrentUser);
|
||||
|
||||
useEffect(() => {
|
||||
bootIntercom(currentUser);
|
||||
}, [currentUser?.email]);
|
||||
|
||||
const handleScroll = (e: Event) => {
|
||||
if ((e.target as HTMLDivElement).scrollTop === 0) {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import styled from "styled-components";
|
||||
import { getDebuggerErrors } from "selectors/debuggerSelectors";
|
||||
import LogItem, { getLogItemProps } from "./LogItem";
|
||||
import { BlankState } from "./helpers";
|
||||
import { createMessage, NO_ERRORS } from "constants/messages";
|
||||
import { getCurrentUser } from "selectors/usersSelectors";
|
||||
import { AppState } from "reducers";
|
||||
import { bootIntercom } from "utils/helpers";
|
||||
|
||||
const ContainerWrapper = styled.div`
|
||||
overflow: hidden;
|
||||
|
|
@ -18,7 +21,12 @@ const ListWrapper = styled.div`
|
|||
|
||||
function Errors(props: { hasShortCut?: boolean }) {
|
||||
const errors = useSelector(getDebuggerErrors);
|
||||
const expandId = useSelector((state: any) => state.ui.debugger.expandId);
|
||||
const expandId = useSelector((state: AppState) => state.ui.debugger.expandId);
|
||||
const currentUser = useSelector(getCurrentUser);
|
||||
|
||||
useEffect(() => {
|
||||
bootIntercom(currentUser);
|
||||
}, [currentUser?.email]);
|
||||
|
||||
return (
|
||||
<ContainerWrapper>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Collapse, Position } from "@blueprintjs/core";
|
||||
import { Classes } from "components/ads/common";
|
||||
import Icon, { IconName, IconSize } from "components/ads/Icon";
|
||||
import { Message, Severity, SourceEntity } from "entities/AppsmithConsole";
|
||||
import { Log, Message, Severity, SourceEntity } from "entities/AppsmithConsole";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import ReactJson from "react-json-view";
|
||||
import styled from "styled-components";
|
||||
|
|
@ -16,9 +16,16 @@ import Text, { TextType } from "components/ads/Text";
|
|||
import { getTypographyByKey } from "constants/DefaultTheme";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import TooltipComponent from "components/ads/Tooltip";
|
||||
import { createMessage, TROUBLESHOOT_ISSUE } from "constants/messages";
|
||||
import {
|
||||
createMessage,
|
||||
DEBUGGER_INTERCOM_TEXT,
|
||||
TROUBLESHOOT_ISSUE,
|
||||
} from "constants/messages";
|
||||
import { PropertyEvaluationErrorType } from "utils/DynamicBindingUtils";
|
||||
import { getAppsmithConfigs } from "configs";
|
||||
const { intercomAppID } = getAppsmithConfigs();
|
||||
|
||||
const Log = styled.div<{ collapsed: boolean }>`
|
||||
const Wrapper = styled.div<{ collapsed: boolean }>`
|
||||
padding: 9px 30px;
|
||||
display: flex;
|
||||
|
||||
|
|
@ -142,7 +149,7 @@ const MessageWrapper = styled.div`
|
|||
padding-top: ${(props) => props.theme.spaces[1]}px;
|
||||
`;
|
||||
|
||||
export const getLogItemProps = (e: Message) => {
|
||||
export const getLogItemProps = (e: Log) => {
|
||||
return {
|
||||
icon: SeverityIcon[e.severity] as IconName,
|
||||
iconColor: SeverityIconColor[e.severity],
|
||||
|
|
@ -170,7 +177,7 @@ type LogItemProps = {
|
|||
id?: string;
|
||||
source?: SourceEntity;
|
||||
expand?: boolean;
|
||||
messages: Message["messages"];
|
||||
messages?: Message[];
|
||||
};
|
||||
|
||||
function LogItem(props: LogItemProps) {
|
||||
|
|
@ -188,21 +195,47 @@ function LogItem(props: LogItemProps) {
|
|||
const showToggleIcon = props.state || props.messages;
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const openHelpModal = useCallback((e, message?: string) => {
|
||||
const onLogClick = useCallback((e, error?: Message) => {
|
||||
e.stopPropagation();
|
||||
const text = message || props.text;
|
||||
|
||||
AnalyticsUtil.logEvent("OPEN_OMNIBAR", {
|
||||
source: "DEBUGGER",
|
||||
searchTerm: text,
|
||||
});
|
||||
dispatch(setGlobalSearchQuery(text || ""));
|
||||
dispatch(toggleShowGlobalSearchModal());
|
||||
// If the error message was clicked we use that, else if the wand icon is clicked
|
||||
// we use the first error "Message" in the list
|
||||
// This is of type Message { message: string; type?: ErrorType; }
|
||||
const focusedError =
|
||||
error ||
|
||||
(props.messages && props.messages.length ? props.messages[0] : undefined);
|
||||
const text = focusedError?.message || props.text;
|
||||
|
||||
switch (focusedError?.type) {
|
||||
case PropertyEvaluationErrorType.PARSE:
|
||||
case PropertyEvaluationErrorType.LINT:
|
||||
// Search google for the error message
|
||||
window.open("http://google.com/search?q=" + text);
|
||||
break;
|
||||
case PropertyEvaluationErrorType.VALIDATION:
|
||||
// Search through the omnibar
|
||||
AnalyticsUtil.logEvent("OPEN_OMNIBAR", {
|
||||
source: "DEBUGGER",
|
||||
searchTerm: text,
|
||||
errorType: PropertyEvaluationErrorType.VALIDATION,
|
||||
});
|
||||
dispatch(setGlobalSearchQuery(text || ""));
|
||||
dispatch(toggleShowGlobalSearchModal());
|
||||
break;
|
||||
default:
|
||||
// Prefill the error in intercom
|
||||
if (intercomAppID && window.Intercom) {
|
||||
window.Intercom(
|
||||
"showNewMessage",
|
||||
createMessage(DEBUGGER_INTERCOM_TEXT, text),
|
||||
);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
const messages = props.messages || [];
|
||||
|
||||
return (
|
||||
<Log
|
||||
<Wrapper
|
||||
className={props.severity}
|
||||
collapsed={!isOpen}
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
|
|
@ -244,7 +277,7 @@ function LogItem(props: LogItemProps) {
|
|||
className={Classes.ICON}
|
||||
fillColor={props.iconColor}
|
||||
name={"wand"}
|
||||
onClick={openHelpModal}
|
||||
onClick={onLogClick}
|
||||
size={IconSize.MEDIUM}
|
||||
/>
|
||||
</TooltipComponent>
|
||||
|
|
@ -257,7 +290,7 @@ function LogItem(props: LogItemProps) {
|
|||
<MessageWrapper key={e.message}>
|
||||
<span
|
||||
className="debugger-message"
|
||||
onClick={(event) => openHelpModal(event, e.message)}
|
||||
onClick={(event) => onLogClick(event, e)}
|
||||
>
|
||||
{e.message}
|
||||
</span>
|
||||
|
|
@ -283,7 +316,7 @@ function LogItem(props: LogItemProps) {
|
|||
uiComponent={DebuggerLinkUI.ENTITY_NAME}
|
||||
/>
|
||||
)}
|
||||
</Log>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Message, Severity } from "entities/AppsmithConsole";
|
||||
import { Log, Severity } from "entities/AppsmithConsole";
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { getTypographyByKey } from "constants/DefaultTheme";
|
||||
|
|
@ -125,7 +125,7 @@ export function getDependencyChain(
|
|||
|
||||
export const doesEntityHaveErrors = (
|
||||
entityId: string,
|
||||
debuggerErrors: Record<string, Message>,
|
||||
debuggerErrors: Record<string, Log>,
|
||||
) => {
|
||||
const ids = Object.keys(debuggerErrors);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useParams } from "react-router";
|
||||
import { ENTITY_TYPE, Message } from "entities/AppsmithConsole";
|
||||
import { ENTITY_TYPE, Log } from "entities/AppsmithConsole";
|
||||
import { AppState } from "reducers";
|
||||
import { getActionConfig } from "pages/Editor/Explorer/Actions/helpers";
|
||||
import { useNavigateToWidget } from "pages/Editor/Explorer/Widgets/useNavigateToWidget";
|
||||
|
|
@ -33,11 +33,11 @@ export const useFilteredLogs = (query: string, filter?: any) => {
|
|||
let logs = useSelector((state: AppState) => state.ui.debugger.logs);
|
||||
|
||||
if (filter) {
|
||||
logs = logs.filter((log: Message) => log.severity === filter);
|
||||
logs = logs.filter((log) => log.severity === filter);
|
||||
}
|
||||
|
||||
if (query) {
|
||||
logs = logs.filter((log: Message) => {
|
||||
logs = logs.filter((log) => {
|
||||
if (log.source?.name)
|
||||
return (
|
||||
log.source?.name.toUpperCase().indexOf(query.toUpperCase()) !== -1
|
||||
|
|
@ -48,9 +48,9 @@ export const useFilteredLogs = (query: string, filter?: any) => {
|
|||
return logs;
|
||||
};
|
||||
|
||||
export const usePagination = (data: Message[], itemsPerPage = 50) => {
|
||||
export const usePagination = (data: Log[], itemsPerPage = 50) => {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [paginatedData, setPaginatedData] = useState<Message[]>([]);
|
||||
const [paginatedData, setPaginatedData] = useState<Log[]>([]);
|
||||
const maxPage = Math.ceil(data.length / itemsPerPage);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -158,9 +158,7 @@ export const useEntityLink = () => {
|
|||
|
||||
export const useGetEntityInfo = (name: string) => {
|
||||
const entity = useSelector((state: AppState) => state.evaluations.tree[name]);
|
||||
const debuggerErrors: Record<string, Message> = useSelector(
|
||||
getDebuggerErrors,
|
||||
);
|
||||
const debuggerErrors = useSelector(getDebuggerErrors);
|
||||
const action = useSelector((state: AppState) =>
|
||||
isAction(entity) ? getAction(state, entity.actionId) : undefined,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -133,10 +133,11 @@ export const ReduxActionTypes = {
|
|||
PUBLISH: "PUBLISH",
|
||||
DEBUGGER_LOG: "DEBUGGER_LOG",
|
||||
DEBUGGER_LOG_INIT: "DEBUGGER_LOG_INIT",
|
||||
DEBUGGER_ERROR_LOG: "DEBUGGER_ERROR_LOG",
|
||||
DEBUGGER_UPDATE_ERROR_LOG: "DEBUGGER_UPDATE_ERROR_LOG",
|
||||
DEBUGGER_UPDATE_ERROR_LOGS: "DEBUGGER_UPDATE_ERROR_LOGS",
|
||||
DEBUGGER_ERROR_ANALYTICS: "DEBUGGER_ERROR_ANALYTICS",
|
||||
DEBUGGER_ADD_ERROR_LOG: "DEBUGGER_ADD_ERROR_LOG",
|
||||
DEBUGGER_DELETE_ERROR_LOG: "DEBUGGER_DELETE_ERROR_LOG",
|
||||
DEBUGGER_ADD_ERROR_LOG_INIT: "DEBUGGER_ADD_ERROR_LOG_INIT",
|
||||
DEBUGGER_DELETE_ERROR_LOG_INIT: "DEBUGGER_DELETE_ERROR_LOG_INIT",
|
||||
CLEAR_DEBUGGER_LOGS: "CLEAR_DEBUGGER_LOGS",
|
||||
SHOW_DEBUGGER: "SHOW_DEBUGGER",
|
||||
SET_ACTION_TABS_INITIAL_INDEX: "SET_ACTION_TABS_INITIAL_INDEX",
|
||||
|
|
|
|||
|
|
@ -349,11 +349,15 @@ export const DEBUGGER_ERRORS = () => "Errors";
|
|||
export const DEBUGGER_LOGS = () => "Logs";
|
||||
export const INSPECT_ENTITY = () => "Inspect Entity";
|
||||
export const INSPECT_ENTITY_BLANK_STATE = () => "Select an entity to inspect";
|
||||
export const VALUE_IS_INVALID = (propertyPath: string) =>
|
||||
`The value at ${propertyPath} is invalid`;
|
||||
export const ACTION_CONFIGURATION_UPDATED = () => "Configuration updated";
|
||||
export const WIDGET_PROPERTIES_UPDATED = () => "Widget properties were updated";
|
||||
export const EMPTY_RESPONSE_FIRST_HALF = () => "🙌 Click on";
|
||||
export const EMPTY_RESPONSE_LAST_HALF = () => "to get a response";
|
||||
export const INVALID_EMAIL = () => "Please enter a valid email";
|
||||
export const DEBUGGER_INTERCOM_TEXT = (text: string) =>
|
||||
`Hi, \nI'm facing the following error on appsmith, can you please help? \n\n${text}`;
|
||||
|
||||
export const TROUBLESHOOT_ISSUE = () => "Troubleshoot issue";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
import { ActionableError } from "entities/AppsmithConsole";
|
||||
|
||||
export enum ActionError {
|
||||
EXECUTION_TIMEOUT = "action:execution:timeout",
|
||||
}
|
||||
|
||||
export interface TimeoutError extends ActionableError {
|
||||
type: ActionError.EXECUTION_TIMEOUT;
|
||||
timeoutMs: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,5 @@
|
|||
import { ActionableError } from "entities/AppsmithConsole";
|
||||
|
||||
export enum BindingError {
|
||||
SYNTAX = "binding:syntax",
|
||||
UNKNOWN_VARIABLE = "binding:unknown_variable",
|
||||
DISALLOWED_FUNCTION = "binding:disallowed_function",
|
||||
}
|
||||
|
||||
interface BaseBindingError extends ActionableError {
|
||||
lineNumber: number;
|
||||
position: number;
|
||||
}
|
||||
|
||||
export interface SyntaxError extends BaseBindingError {
|
||||
type: BindingError.SYNTAX;
|
||||
}
|
||||
|
||||
export interface UnknownVariableError extends BaseBindingError {
|
||||
type: BindingError.UNKNOWN_VARIABLE;
|
||||
variableName: string;
|
||||
}
|
||||
|
||||
export interface DisallowedFunctionError extends BaseBindingError {
|
||||
type: BindingError.DISALLOWED_FUNCTION;
|
||||
functionName: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
import { ActionableError, SourceEntity } from "entities/AppsmithConsole";
|
||||
|
||||
export enum EvalError {
|
||||
CYCLIC = "eval:cyclic",
|
||||
}
|
||||
|
||||
export interface CyclicDependencyError extends ActionableError {
|
||||
type: EvalError.CYCLIC;
|
||||
entities: SourceEntity[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import { ReduxAction } from "constants/ReduxActionConstants";
|
||||
import { BindingError } from "entities/AppsmithConsole/binding";
|
||||
import { ActionError } from "entities/AppsmithConsole/action";
|
||||
import { WidgetError } from "entities/AppsmithConsole/widget";
|
||||
import { EvalError } from "entities/AppsmithConsole/eval";
|
||||
import LOG_TYPE from "./logtype";
|
||||
import { PropertyEvaluationErrorType } from "utils/DynamicBindingUtils";
|
||||
|
||||
export enum ENTITY_TYPE {
|
||||
ACTION = "ACTION",
|
||||
|
|
@ -11,7 +8,11 @@ export enum ENTITY_TYPE {
|
|||
WIDGET = "WIDGET",
|
||||
}
|
||||
|
||||
export type ErrorType = BindingError | ActionError | WidgetError | EvalError;
|
||||
export enum PLATFORM_ERROR {
|
||||
PLUGIN_EXECUTION = "PLUGIN_EXECUTION",
|
||||
}
|
||||
|
||||
export type ErrorType = PropertyEvaluationErrorType | PLATFORM_ERROR;
|
||||
|
||||
export enum Severity {
|
||||
// Everything, irrespective of what the user should see or not
|
||||
|
|
@ -47,17 +48,13 @@ export interface SourceEntity {
|
|||
}
|
||||
|
||||
export interface LogActionPayload {
|
||||
// Log id, used for updating or deleting
|
||||
id?: string;
|
||||
// What is the log about. Is it a datasource update, widget update, eval error etc.
|
||||
logType?: LOG_TYPE;
|
||||
text: string;
|
||||
messages?: Array<Message>;
|
||||
// Time taken for the event to complete
|
||||
messages?: Array<{
|
||||
// More contextual message than `text`
|
||||
message: string;
|
||||
// The section of code being referred to
|
||||
// codeSegment?: string;
|
||||
}>;
|
||||
|
||||
timeTaken?: string;
|
||||
// "where" source entity and propertyPsath.
|
||||
source?: SourceEntity;
|
||||
|
|
@ -67,7 +64,15 @@ export interface LogActionPayload {
|
|||
analytics?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface Message extends LogActionPayload {
|
||||
export interface Message {
|
||||
// More contextual message than `text`
|
||||
message: string;
|
||||
type?: ErrorType;
|
||||
// The section of code being referred to
|
||||
// codeSegment?: string;
|
||||
}
|
||||
|
||||
export interface Log extends LogActionPayload {
|
||||
severity: Severity;
|
||||
// "when" did this event happen
|
||||
timestamp: string;
|
||||
|
|
@ -100,12 +105,3 @@ export interface Message extends LogActionPayload {
|
|||
* ]
|
||||
* }
|
||||
*/
|
||||
export interface ActionableError extends Message {
|
||||
// Error type of the event.
|
||||
type: ErrorType;
|
||||
|
||||
severity: Severity.ERROR;
|
||||
|
||||
// Actions a user can take to resolve this issue
|
||||
userActions: Array<UserAction>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,15 @@ import React, { useEffect } from "react";
|
|||
import styled, { createGlobalStyle, withTheme } from "styled-components";
|
||||
import { Popover, Position } from "@blueprintjs/core";
|
||||
|
||||
import DocumentationSearch, {
|
||||
bootIntercom,
|
||||
} from "components/designSystems/appsmith/help/DocumentationSearch";
|
||||
import DocumentationSearch from "components/designSystems/appsmith/help/DocumentationSearch";
|
||||
import Icon, { IconSize } from "components/ads/Icon";
|
||||
|
||||
import { HELP_MODAL_WIDTH } from "constants/HelpConstants";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { Theme } from "constants/DefaultTheme";
|
||||
import { getAppsmithConfigs } from "../../configs";
|
||||
import { getCurrentUser } from "../../selectors/usersSelectors";
|
||||
import { useSelector } from "react-redux";
|
||||
import { bootIntercom } from "utils/helpers";
|
||||
|
||||
const HelpPopoverStyle = createGlobalStyle`
|
||||
.bp3-popover.bp3-minimal.navbar-help-popover {
|
||||
|
|
@ -47,12 +45,11 @@ const onOpened = () => {
|
|||
AnalyticsUtil.logEvent("OPEN_HELP", { page: "Editor" });
|
||||
};
|
||||
|
||||
const { intercomAppID } = getAppsmithConfigs();
|
||||
function HelpButton() {
|
||||
const user = useSelector(getCurrentUser);
|
||||
|
||||
useEffect(() => {
|
||||
bootIntercom(intercomAppID, user);
|
||||
bootIntercom(user);
|
||||
}, [user?.email]);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import {
|
|||
getDependenciesFromInverseDependencies,
|
||||
} from "components/editorComponents/Debugger/helpers";
|
||||
import { getDebuggerErrors } from "selectors/debuggerSelectors";
|
||||
import { ENTITY_TYPE, Message } from "entities/AppsmithConsole";
|
||||
import { ENTITY_TYPE, Log } from "entities/AppsmithConsole";
|
||||
import { DebugButton } from "components/editorComponents/Debugger/DebugCTA";
|
||||
import { showDebugger } from "actions/debuggerActions";
|
||||
import { setActionTabsInitialIndex } from "actions/actionActions";
|
||||
|
|
@ -179,7 +179,7 @@ type TriggerNodeProps = DefaultDropDownValueNodeProps & {
|
|||
|
||||
const doConnectionsHaveErrors = (
|
||||
options: DropdownOption[],
|
||||
debuggerErrors: Record<string, Message>,
|
||||
debuggerErrors: Record<string, Log>,
|
||||
) => {
|
||||
return options.some((option) =>
|
||||
doesEntityHaveErrors(option.value as string, debuggerErrors),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { createReducer } from "utils/AppsmithUtils";
|
||||
import { Message, Severity } from "entities/AppsmithConsole";
|
||||
import { Log, Severity } from "entities/AppsmithConsole";
|
||||
import { ReduxAction, ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
import { get, merge, isEmpty, omit, isUndefined } from "lodash";
|
||||
import LOG_TYPE from "entities/AppsmithConsole/logtype";
|
||||
import { omit, isUndefined } from "lodash";
|
||||
|
||||
const initialState: DebuggerReduxState = {
|
||||
logs: [],
|
||||
|
|
@ -15,7 +14,7 @@ const initialState: DebuggerReduxState = {
|
|||
const debuggerReducer = createReducer(initialState, {
|
||||
[ReduxActionTypes.DEBUGGER_LOG]: (
|
||||
state: DebuggerReduxState,
|
||||
action: ReduxAction<Message>,
|
||||
action: ReduxAction<Log>,
|
||||
) => {
|
||||
const isError = action.payload.severity === Severity.ERROR;
|
||||
|
||||
|
|
@ -41,70 +40,28 @@ const debuggerReducer = createReducer(initialState, {
|
|||
isOpen: isUndefined(action.payload) ? !state.isOpen : action.payload,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.DEBUGGER_ERROR_LOG]: (
|
||||
[ReduxActionTypes.DEBUGGER_ADD_ERROR_LOG]: (
|
||||
state: DebuggerReduxState,
|
||||
action: ReduxAction<Message>,
|
||||
action: ReduxAction<Log>,
|
||||
) => {
|
||||
if (!action.payload.source) return state;
|
||||
|
||||
const entityId = action.payload.source.id;
|
||||
const id =
|
||||
action.payload.logType === LOG_TYPE.WIDGET_PROPERTY_VALIDATION_ERROR ||
|
||||
action.payload.logType === LOG_TYPE.EVAL_ERROR
|
||||
? `${entityId}-${action.payload.source.propertyPath}`
|
||||
: entityId;
|
||||
const previousState = get(state.errors, id, {});
|
||||
if (!action.payload.id) return state;
|
||||
|
||||
return {
|
||||
...state,
|
||||
errors: {
|
||||
...state.errors,
|
||||
[id]: {
|
||||
...merge(previousState, action.payload),
|
||||
},
|
||||
[action.payload.id]: action.payload,
|
||||
},
|
||||
expandId: id,
|
||||
expandId: action.payload.id,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.DEBUGGER_UPDATE_ERROR_LOG]: (
|
||||
[ReduxActionTypes.DEBUGGER_DELETE_ERROR_LOG]: (
|
||||
state: DebuggerReduxState,
|
||||
action: ReduxAction<Message>,
|
||||
) => {
|
||||
if (!action.payload.source) return state;
|
||||
|
||||
const entityId = action.payload.source.id;
|
||||
const isWidgetErrorLog =
|
||||
action.payload.logType === LOG_TYPE.WIDGET_PROPERTY_VALIDATION_ERROR ||
|
||||
action.payload.logType === LOG_TYPE.EVAL_ERROR;
|
||||
const id = isWidgetErrorLog
|
||||
? `${entityId}-${action.payload.source.propertyPath}`
|
||||
: entityId;
|
||||
|
||||
if (isEmpty(action.payload.state)) {
|
||||
return {
|
||||
...state,
|
||||
errors: omit(state.errors, id),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
errors: {
|
||||
...state.errors,
|
||||
[id]: {
|
||||
...action.payload,
|
||||
},
|
||||
},
|
||||
expandId: id,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.DEBUGGER_UPDATE_ERROR_LOGS]: (
|
||||
state: DebuggerReduxState,
|
||||
action: ReduxAction<Message>,
|
||||
action: ReduxAction<string>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
errors: { ...action.payload },
|
||||
errors: omit(state.errors, action.payload),
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.INIT_CANVAS_LAYOUT]: () => {
|
||||
|
|
@ -115,10 +72,10 @@ const debuggerReducer = createReducer(initialState, {
|
|||
});
|
||||
|
||||
export interface DebuggerReduxState {
|
||||
logs: Message[];
|
||||
logs: Log[];
|
||||
errorCount: number;
|
||||
isOpen: boolean;
|
||||
errors: Record<string, Message>;
|
||||
errors: Record<string, Log>;
|
||||
expandId: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ import {
|
|||
resetWidgetMetaProperty,
|
||||
} from "actions/metaActions";
|
||||
import AppsmithConsole from "utils/AppsmithConsole";
|
||||
import { ENTITY_TYPE } from "entities/AppsmithConsole";
|
||||
import { ENTITY_TYPE, PLATFORM_ERROR } from "entities/AppsmithConsole";
|
||||
import LOG_TYPE from "entities/AppsmithConsole/logtype";
|
||||
import { matchPath } from "react-router";
|
||||
import { setDataUrl } from "./PageSagas";
|
||||
|
|
@ -565,7 +565,8 @@ export function* executeActionSaga(
|
|||
}),
|
||||
);
|
||||
if (isErrorResponse(response)) {
|
||||
AppsmithConsole.error({
|
||||
AppsmithConsole.addError({
|
||||
id: actionId,
|
||||
logType: LOG_TYPE.ACTION_EXECUTION_ERROR,
|
||||
text: `Execution failed with status ${response.data.statusCode}`,
|
||||
source: {
|
||||
|
|
@ -574,7 +575,12 @@ export function* executeActionSaga(
|
|||
id: actionId,
|
||||
},
|
||||
state: response.data?.request ?? null,
|
||||
messages: [{ message: payload.body as string }],
|
||||
messages: [
|
||||
{
|
||||
message: payload.body as string,
|
||||
type: PLATFORM_ERROR.PLUGIN_EXECUTION,
|
||||
},
|
||||
],
|
||||
});
|
||||
PerformanceTracker.stopAsyncTracking(
|
||||
PerformanceTransactionName.EXECUTE_ACTION,
|
||||
|
|
@ -902,7 +908,8 @@ function* runActionSaga(
|
|||
},
|
||||
});
|
||||
} else {
|
||||
AppsmithConsole.error({
|
||||
AppsmithConsole.addError({
|
||||
id: actionId,
|
||||
logType: LOG_TYPE.ACTION_EXECUTION_ERROR,
|
||||
text: `Execution failed with status ${response.data.statusCode}`,
|
||||
source: {
|
||||
|
|
@ -915,6 +922,7 @@ function* runActionSaga(
|
|||
message: !isString(payload.body)
|
||||
? JSON.stringify(payload.body)
|
||||
: payload.body,
|
||||
type: PLATFORM_ERROR.PLUGIN_EXECUTION,
|
||||
},
|
||||
],
|
||||
state: response.data?.request ?? null,
|
||||
|
|
@ -931,7 +939,8 @@ function* runActionSaga(
|
|||
error = response.data.body.toString();
|
||||
}
|
||||
|
||||
AppsmithConsole.error({
|
||||
AppsmithConsole.addError({
|
||||
id: actionId,
|
||||
logType: LOG_TYPE.ACTION_EXECUTION_ERROR,
|
||||
text: `Execution failed with status ${response.data.statusCode} `,
|
||||
source: {
|
||||
|
|
@ -1016,7 +1025,8 @@ function* executePageLoadAction(pageAction: PageAction) {
|
|||
message += `\nERROR: "${body}"`;
|
||||
}
|
||||
|
||||
AppsmithConsole.error({
|
||||
AppsmithConsole.addError({
|
||||
id: pageAction.id,
|
||||
logType: LOG_TYPE.ACTION_EXECUTION_ERROR,
|
||||
text: `Execution failed with status ${response.data.statusCode}`,
|
||||
source: {
|
||||
|
|
@ -1025,7 +1035,12 @@ function* executePageLoadAction(pageAction: PageAction) {
|
|||
id: pageAction.id,
|
||||
},
|
||||
state: response.data?.request ?? null,
|
||||
messages: [{ message: JSON.stringify(body) }],
|
||||
messages: [
|
||||
{
|
||||
message: JSON.stringify(body),
|
||||
type: PLATFORM_ERROR.PLUGIN_EXECUTION,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
yield put(
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
import {
|
||||
addErrorLog,
|
||||
debuggerLog,
|
||||
errorLog,
|
||||
logDebuggerErrorAnalytics,
|
||||
debuggerLogInit,
|
||||
deleteErrorLog,
|
||||
LogDebuggerErrorAnalyticsPayload,
|
||||
updateErrorLog,
|
||||
} from "actions/debuggerActions";
|
||||
import { ReduxAction, ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
import {
|
||||
ENTITY_TYPE,
|
||||
LogActionPayload,
|
||||
Message,
|
||||
} from "entities/AppsmithConsole";
|
||||
import { ENTITY_TYPE, Log, LogActionPayload } from "entities/AppsmithConsole";
|
||||
import {
|
||||
all,
|
||||
call,
|
||||
|
|
@ -20,13 +16,9 @@ import {
|
|||
take,
|
||||
takeEvery,
|
||||
} from "redux-saga/effects";
|
||||
import { get, set } from "lodash";
|
||||
import { findIndex, get, isMatch, set } from "lodash";
|
||||
import { getDebuggerErrors } from "selectors/debuggerSelectors";
|
||||
import {
|
||||
getAction,
|
||||
getPlugin,
|
||||
getPluginNameFromId,
|
||||
} from "selectors/entitiesSelector";
|
||||
import { getAction, getPlugin } from "selectors/entitiesSelector";
|
||||
import { Action, PluginType } from "entities/Action";
|
||||
import LOG_TYPE from "entities/AppsmithConsole/logtype";
|
||||
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||
|
|
@ -50,6 +42,7 @@ import { Plugin } from "api/PluginApi";
|
|||
import { getCurrentPageId } from "selectors/editorSelectors";
|
||||
import { getWidget } from "./selectors";
|
||||
import { WidgetProps } from "widgets/BaseWidget";
|
||||
import AppsmithConsole from "utils/AppsmithConsole";
|
||||
|
||||
// Saga to format action request values to be shown in the debugger
|
||||
function* formatActionRequestSaga(
|
||||
|
|
@ -103,62 +96,29 @@ function* formatActionRequestSaga(
|
|||
}
|
||||
}
|
||||
|
||||
function* onEntityDeleteSaga(payload: Message) {
|
||||
function* onEntityDeleteSaga(payload: Log) {
|
||||
const source = payload.source;
|
||||
|
||||
if (!source) {
|
||||
yield put(debuggerLog(payload));
|
||||
return;
|
||||
}
|
||||
const currentPageId = yield select(getCurrentPageId);
|
||||
let pluginName: string = yield select(
|
||||
getPluginNameFromId,
|
||||
payload?.analytics?.pluginId,
|
||||
);
|
||||
|
||||
const errors: Record<string, Message> = yield select(getDebuggerErrors);
|
||||
const errors: Record<string, Log> = yield select(getDebuggerErrors);
|
||||
const errorIds = Object.keys(errors);
|
||||
const updatedErrors: any = {};
|
||||
|
||||
errorIds.map((e) => {
|
||||
const includes = e.includes(source.id);
|
||||
|
||||
if (!includes) {
|
||||
updatedErrors[e] = errors[e];
|
||||
} else {
|
||||
// If the error is being removed here
|
||||
// need to send an analytics event for the same
|
||||
const error = errors[e];
|
||||
pluginName = pluginName.replace(/ /g, "");
|
||||
|
||||
if (source.type === ENTITY_TYPE.ACTION) {
|
||||
AnalyticsUtil.logEvent("DEBUGGER_RESOLVED_ERROR", {
|
||||
entityType: pluginName,
|
||||
propertyPath: `${pluginName}.${error.source?.propertyPath ?? ""}`,
|
||||
errorMessages: error.messages,
|
||||
pageId: currentPageId,
|
||||
});
|
||||
} else if (source.type === ENTITY_TYPE.WIDGET) {
|
||||
const widgetType = error?.analytics?.widgetType;
|
||||
|
||||
AnalyticsUtil.logEvent("DEBUGGER_RESOLVED_ERROR", {
|
||||
entityType: widgetType,
|
||||
propertyPath: `${widgetType}.${error.source?.propertyPath ?? ""}`,
|
||||
errorMessages: error.messages,
|
||||
pageId: currentPageId,
|
||||
});
|
||||
}
|
||||
if (includes) {
|
||||
AppsmithConsole.deleteError(e, payload.analytics);
|
||||
}
|
||||
});
|
||||
|
||||
yield put({
|
||||
type: ReduxActionTypes.DEBUGGER_UPDATE_ERROR_LOGS,
|
||||
payload: updatedErrors,
|
||||
});
|
||||
yield put(debuggerLog(payload));
|
||||
}
|
||||
|
||||
function* logDependentEntityProperties(payload: Message) {
|
||||
function* logDependentEntityProperties(payload: Log) {
|
||||
const { source, state } = payload;
|
||||
if (!state || !source) return;
|
||||
|
||||
|
|
@ -207,11 +167,8 @@ function* logDependentEntityProperties(payload: Message) {
|
|||
);
|
||||
}
|
||||
|
||||
function* debuggerLogSaga(action: ReduxAction<Message>) {
|
||||
function* debuggerLogSaga(action: ReduxAction<Log>) {
|
||||
const { payload } = action;
|
||||
const debuggerErrors: Record<string, Message> = yield select(
|
||||
getDebuggerErrors,
|
||||
);
|
||||
|
||||
switch (payload.logType) {
|
||||
case LOG_TYPE.WIDGET_UPDATE:
|
||||
|
|
@ -226,9 +183,7 @@ function* debuggerLogSaga(action: ReduxAction<Message>) {
|
|||
case LOG_TYPE.WIDGET_PROPERTY_VALIDATION_ERROR:
|
||||
if (payload.source && payload.source.propertyPath) {
|
||||
if (payload.text) {
|
||||
yield put(errorLog(payload));
|
||||
|
||||
yield put(debuggerLog(payload));
|
||||
yield put(addErrorLog(payload));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -239,20 +194,7 @@ function* debuggerLogSaga(action: ReduxAction<Message>) {
|
|||
payload,
|
||||
"state",
|
||||
);
|
||||
if (!((payload.source?.id as string) in debuggerErrors)) {
|
||||
yield put(
|
||||
logDebuggerErrorAnalytics({
|
||||
eventName: "DEBUGGER_NEW_ERROR",
|
||||
errorMessages: payload.messages ?? [],
|
||||
entityType: ENTITY_TYPE.ACTION,
|
||||
entityId: payload.source?.id ?? "",
|
||||
entityName: payload.source?.name ?? "",
|
||||
propertyPath: "",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
yield put(errorLog(formattedLog));
|
||||
yield put(addErrorLog(formattedLog));
|
||||
yield put(debuggerLog(formattedLog));
|
||||
}
|
||||
break;
|
||||
|
|
@ -264,25 +206,7 @@ function* debuggerLogSaga(action: ReduxAction<Message>) {
|
|||
"state.request",
|
||||
);
|
||||
|
||||
if ((payload.source?.id as string) in debuggerErrors) {
|
||||
yield put(
|
||||
logDebuggerErrorAnalytics({
|
||||
eventName: "DEBUGGER_RESOLVED_ERROR",
|
||||
errorMessages:
|
||||
debuggerErrors[payload.source?.id ?? ""].messages ?? [],
|
||||
entityType: ENTITY_TYPE.ACTION,
|
||||
entityId: payload.source?.id ?? "",
|
||||
entityName: payload.source?.name ?? "",
|
||||
propertyPath: "",
|
||||
}),
|
||||
);
|
||||
}
|
||||
yield put(
|
||||
updateErrorLog({
|
||||
...payload,
|
||||
state: {},
|
||||
}),
|
||||
);
|
||||
AppsmithConsole.deleteError(payload.source?.id ?? "");
|
||||
|
||||
yield put(debuggerLog(formattedLog));
|
||||
}
|
||||
|
|
@ -304,8 +228,11 @@ function* logDebuggerErrorAnalyticsSaga(
|
|||
const currentPageId = yield select(getCurrentPageId);
|
||||
|
||||
if (payload.entityType === ENTITY_TYPE.WIDGET) {
|
||||
const widget: WidgetProps = yield select(getWidget, payload.entityId);
|
||||
const widgetType = widget.type;
|
||||
const widget: WidgetProps | undefined = yield select(
|
||||
getWidget,
|
||||
payload.entityId,
|
||||
);
|
||||
const widgetType = widget?.type || payload?.analytics?.widgetType || "";
|
||||
const propertyPath = `${widgetType}.${payload.propertyPath}`;
|
||||
|
||||
// Sending widget type for widgets
|
||||
|
|
@ -314,10 +241,16 @@ function* logDebuggerErrorAnalyticsSaga(
|
|||
propertyPath,
|
||||
errorMessages: payload.errorMessages,
|
||||
pageId: currentPageId,
|
||||
errorMessage: payload.errorMessage,
|
||||
errorType: payload.errorType,
|
||||
});
|
||||
} else if (payload.entityType === ENTITY_TYPE.ACTION) {
|
||||
const action: Action = yield select(getAction, payload.entityId);
|
||||
const plugin: Plugin = yield select(getPlugin, action.pluginId);
|
||||
const action: Action | undefined = yield select(
|
||||
getAction,
|
||||
payload.entityId,
|
||||
);
|
||||
const pluginId = action?.pluginId || payload?.analytics?.pluginId || "";
|
||||
const plugin: Plugin = yield select(getPlugin, pluginId);
|
||||
const pluginName = plugin.name.replace(/ /g, "");
|
||||
let propertyPath = `${pluginName}`;
|
||||
|
||||
|
|
@ -331,6 +264,8 @@ function* logDebuggerErrorAnalyticsSaga(
|
|||
propertyPath,
|
||||
errorMessages: payload.errorMessages,
|
||||
pageId: currentPageId,
|
||||
errorMessage: payload.errorMessage,
|
||||
errorType: payload.errorType,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -338,6 +273,147 @@ function* logDebuggerErrorAnalyticsSaga(
|
|||
}
|
||||
}
|
||||
|
||||
function* addDebuggerErrorLogSaga(action: ReduxAction<Log>) {
|
||||
const payload = action.payload;
|
||||
const errors: Record<string, Log> = yield select(getDebuggerErrors);
|
||||
|
||||
yield put(debuggerLogInit(payload));
|
||||
|
||||
if (!payload.source || !payload.id) return;
|
||||
|
||||
const analyticsPayload = {
|
||||
entityName: payload.source.name,
|
||||
entityType: payload.source.type,
|
||||
entityId: payload.source.id,
|
||||
propertyPath: payload.source.propertyPath ?? "",
|
||||
};
|
||||
|
||||
// If this is a new error
|
||||
if (!(payload.id in errors)) {
|
||||
const errorMessages = payload.messages ?? [];
|
||||
|
||||
yield put({
|
||||
type: ReduxActionTypes.DEBUGGER_ERROR_ANALYTICS,
|
||||
payload: {
|
||||
...analyticsPayload,
|
||||
eventName: "DEBUGGER_NEW_ERROR",
|
||||
errorMessages: payload.messages,
|
||||
},
|
||||
});
|
||||
|
||||
// Log analytics for new error messages
|
||||
if (errorMessages.length && payload) {
|
||||
yield all(
|
||||
errorMessages.map((errorMessage) =>
|
||||
put({
|
||||
type: ReduxActionTypes.DEBUGGER_ERROR_ANALYTICS,
|
||||
payload: {
|
||||
...analyticsPayload,
|
||||
eventName: "DEBUGGER_NEW_ERROR_MESSAGE",
|
||||
errorMessage: errorMessage.message,
|
||||
errorType: errorMessage.type,
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const updatedErrorMessages = payload.messages ?? [];
|
||||
const existingErrorMessages = errors[payload.id].messages ?? [];
|
||||
// Log new error messages
|
||||
yield all(
|
||||
updatedErrorMessages.map((updatedErrorMessage) => {
|
||||
const exists = findIndex(
|
||||
existingErrorMessages,
|
||||
(existingErrorMessage) => {
|
||||
return isMatch(existingErrorMessage, updatedErrorMessage);
|
||||
},
|
||||
);
|
||||
|
||||
if (exists < 0) {
|
||||
return put({
|
||||
type: ReduxActionTypes.DEBUGGER_ERROR_ANALYTICS,
|
||||
payload: {
|
||||
...analyticsPayload,
|
||||
eventName: "DEBUGGER_NEW_ERROR_MESSAGE",
|
||||
errorMessage: updatedErrorMessage.message,
|
||||
errorType: updatedErrorMessage.type,
|
||||
},
|
||||
});
|
||||
}
|
||||
}),
|
||||
);
|
||||
// Log resolved error messages
|
||||
yield all(
|
||||
existingErrorMessages.map((existingErrorMessage) => {
|
||||
const exists = findIndex(
|
||||
updatedErrorMessages,
|
||||
(updatedErrorMessage) => {
|
||||
return isMatch(updatedErrorMessage, existingErrorMessage);
|
||||
},
|
||||
);
|
||||
|
||||
if (exists < 0) {
|
||||
return put({
|
||||
type: ReduxActionTypes.DEBUGGER_ERROR_ANALYTICS,
|
||||
payload: {
|
||||
...analyticsPayload,
|
||||
eventName: "DEBUGGER_RESOLVED_ERROR_MESSAGE",
|
||||
errorMessage: existingErrorMessage.message,
|
||||
errorType: existingErrorMessage.type,
|
||||
},
|
||||
});
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function* deleteDebuggerErrorLogSaga(
|
||||
action: ReduxAction<{ id: string; analytics: Log["analytics"] }>,
|
||||
) {
|
||||
const errors: Record<string, Log> = yield select(getDebuggerErrors);
|
||||
const error = errors[action.payload.id];
|
||||
|
||||
if (!error.source) return;
|
||||
|
||||
const analyticsPayload = {
|
||||
entityName: error.source.name,
|
||||
entityType: error.source.type,
|
||||
entityId: error.source.id,
|
||||
propertyPath: error.source.propertyPath ?? "",
|
||||
analytics: action.payload.analytics,
|
||||
};
|
||||
const errorMessages = error.messages;
|
||||
|
||||
yield put({
|
||||
type: ReduxActionTypes.DEBUGGER_ERROR_ANALYTICS,
|
||||
payload: {
|
||||
...analyticsPayload,
|
||||
eventName: "DEBUGGER_RESOLVED_ERROR",
|
||||
errorMessages,
|
||||
},
|
||||
});
|
||||
|
||||
if (errorMessages) {
|
||||
yield all(
|
||||
errorMessages.map((errorMessage) => {
|
||||
return put({
|
||||
type: ReduxActionTypes.DEBUGGER_ERROR_ANALYTICS,
|
||||
payload: {
|
||||
...analyticsPayload,
|
||||
eventName: "DEBUGGER_RESOLVED_ERROR_MESSAGE",
|
||||
errorMessage: errorMessage.message,
|
||||
errorType: errorMessage.type,
|
||||
},
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
yield put(deleteErrorLog(action.payload.id));
|
||||
}
|
||||
|
||||
export default function* debuggerSagasListeners() {
|
||||
yield all([
|
||||
takeEvery(ReduxActionTypes.DEBUGGER_LOG_INIT, debuggerLogSaga),
|
||||
|
|
@ -345,5 +421,13 @@ export default function* debuggerSagasListeners() {
|
|||
ReduxActionTypes.DEBUGGER_ERROR_ANALYTICS,
|
||||
logDebuggerErrorAnalyticsSaga,
|
||||
),
|
||||
takeEvery(
|
||||
ReduxActionTypes.DEBUGGER_ADD_ERROR_LOG_INIT,
|
||||
addDebuggerErrorLogSaga,
|
||||
),
|
||||
takeEvery(
|
||||
ReduxActionTypes.DEBUGGER_DELETE_ERROR_LOG_INIT,
|
||||
deleteDebuggerErrorLogSaga,
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ENTITY_TYPE, Message } from "entities/AppsmithConsole";
|
||||
import { ENTITY_TYPE, Log } from "entities/AppsmithConsole";
|
||||
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||
import {
|
||||
DataTreeDiff,
|
||||
|
|
@ -13,16 +13,13 @@ import {
|
|||
EvaluationError,
|
||||
getEvalErrorPath,
|
||||
getEvalValuePath,
|
||||
PropertyEvalErrorTypeDebugMessage,
|
||||
PropertyEvaluationErrorType,
|
||||
} from "utils/DynamicBindingUtils";
|
||||
import _ from "lodash";
|
||||
import { find, get, some } from "lodash";
|
||||
import LOG_TYPE from "../entities/AppsmithConsole/logtype";
|
||||
import moment from "moment/moment";
|
||||
import { put, select } from "redux-saga/effects";
|
||||
import {
|
||||
ReduxAction,
|
||||
ReduxActionTypes,
|
||||
ReduxActionWithoutPayload,
|
||||
} from "constants/ReduxActionConstants";
|
||||
import { Toaster } from "components/ads/Toast";
|
||||
|
|
@ -34,6 +31,7 @@ import {
|
|||
createMessage,
|
||||
ERROR_EVAL_ERROR_GENERIC,
|
||||
ERROR_EVAL_TRIGGER,
|
||||
VALUE_IS_INVALID,
|
||||
} from "constants/messages";
|
||||
import log from "loglevel";
|
||||
import { AppState } from "reducers";
|
||||
|
|
@ -41,17 +39,15 @@ import { getAppMode } from "selectors/applicationSelectors";
|
|||
import { APP_MODE } from "entities/App";
|
||||
import { dataTreeTypeDefCreator } from "utils/autocomplete/dataTreeTypeDefCreator";
|
||||
import TernServer from "utils/autocomplete/TernServer";
|
||||
import { logDebuggerErrorAnalytics } from "actions/debuggerActions";
|
||||
import store from "../store";
|
||||
|
||||
const getDebuggerErrors = (state: AppState) => state.ui.debugger.errors;
|
||||
|
||||
function getLatestEvalPropertyErrors(
|
||||
currentDebuggerErrors: Record<string, Message>,
|
||||
function logLatestEvalPropertyErrors(
|
||||
currentDebuggerErrors: Record<string, Log>,
|
||||
dataTree: DataTree,
|
||||
evaluationOrder: Array<string>,
|
||||
) {
|
||||
const updatedDebuggerErrors: Record<string, Message> = {
|
||||
const updatedDebuggerErrors: Record<string, Log> = {
|
||||
...currentDebuggerErrors,
|
||||
};
|
||||
|
||||
|
|
@ -64,12 +60,12 @@ function getLatestEvalPropertyErrors(
|
|||
if (propertyPath in entity.logBlackList) {
|
||||
continue;
|
||||
}
|
||||
const allEvalErrors: EvaluationError[] = _.get(
|
||||
const allEvalErrors: EvaluationError[] = get(
|
||||
entity,
|
||||
getEvalErrorPath(evaluatedPath, false),
|
||||
[],
|
||||
);
|
||||
const evaluatedValue = _.get(
|
||||
const evaluatedValue = get(
|
||||
entity,
|
||||
getEvalValuePath(evaluatedPath, false),
|
||||
);
|
||||
|
|
@ -89,23 +85,17 @@ function getLatestEvalPropertyErrors(
|
|||
|
||||
if (evalErrors.length) {
|
||||
// TODO Rank and set the most critical error
|
||||
const error = evalErrors[0];
|
||||
const errorMessages = evalErrors.map((e) => ({
|
||||
message: e.errorMessage,
|
||||
}));
|
||||
// const error = evalErrors[0];
|
||||
// Reformatting eval errors here to a format usable by the debugger
|
||||
const errorMessages = evalErrors.map((e) => {
|
||||
// Error format required for the debugger
|
||||
const formattedError = {
|
||||
message: e.errorMessage,
|
||||
type: e.errorType,
|
||||
};
|
||||
|
||||
if (!(debuggerKey in updatedDebuggerErrors)) {
|
||||
store.dispatch(
|
||||
logDebuggerErrorAnalytics({
|
||||
eventName: "DEBUGGER_NEW_ERROR",
|
||||
entityId: idField,
|
||||
entityName: nameField,
|
||||
entityType,
|
||||
propertyPath,
|
||||
errorMessages,
|
||||
}),
|
||||
);
|
||||
}
|
||||
return formattedError;
|
||||
});
|
||||
|
||||
const analyticsData = isWidget(entity)
|
||||
? {
|
||||
|
|
@ -114,14 +104,13 @@ function getLatestEvalPropertyErrors(
|
|||
: {};
|
||||
|
||||
// Add or update
|
||||
updatedDebuggerErrors[debuggerKey] = {
|
||||
AppsmithConsole.addError({
|
||||
id: debuggerKey,
|
||||
logType: LOG_TYPE.EVAL_ERROR,
|
||||
text: PropertyEvalErrorTypeDebugMessage[error.errorType](
|
||||
propertyPath,
|
||||
),
|
||||
// Unless the intention is to change the message shown in the debugger please do not
|
||||
// change the text shown here
|
||||
text: createMessage(VALUE_IS_INVALID, propertyPath),
|
||||
messages: errorMessages,
|
||||
severity: error.severity,
|
||||
timestamp: moment().format("hh:mm:ss"),
|
||||
source: {
|
||||
id: idField,
|
||||
name: nameField,
|
||||
|
|
@ -132,25 +121,12 @@ function getLatestEvalPropertyErrors(
|
|||
[propertyPath]: evaluatedValue,
|
||||
},
|
||||
analytics: analyticsData,
|
||||
};
|
||||
});
|
||||
} else if (debuggerKey in updatedDebuggerErrors) {
|
||||
store.dispatch(
|
||||
logDebuggerErrorAnalytics({
|
||||
eventName: "DEBUGGER_RESOLVED_ERROR",
|
||||
entityId: idField,
|
||||
entityName: nameField,
|
||||
entityType,
|
||||
propertyPath:
|
||||
updatedDebuggerErrors[debuggerKey].source?.propertyPath ?? "",
|
||||
errorMessages: updatedDebuggerErrors[debuggerKey].messages ?? [],
|
||||
}),
|
||||
);
|
||||
// Remove
|
||||
delete updatedDebuggerErrors[debuggerKey];
|
||||
AppsmithConsole.deleteError(debuggerKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
return updatedDebuggerErrors;
|
||||
}
|
||||
|
||||
export function* evalErrorHandler(
|
||||
|
|
@ -159,19 +135,15 @@ export function* evalErrorHandler(
|
|||
evaluationOrder?: Array<string>,
|
||||
): any {
|
||||
if (dataTree && evaluationOrder) {
|
||||
const currentDebuggerErrors: Record<string, Message> = yield select(
|
||||
const currentDebuggerErrors: Record<string, Log> = yield select(
|
||||
getDebuggerErrors,
|
||||
);
|
||||
const evalPropertyErrors = getLatestEvalPropertyErrors(
|
||||
// Update latest errors to the debugger
|
||||
logLatestEvalPropertyErrors(
|
||||
currentDebuggerErrors,
|
||||
dataTree,
|
||||
evaluationOrder,
|
||||
);
|
||||
|
||||
yield put({
|
||||
type: ReduxActionTypes.DEBUGGER_UPDATE_ERROR_LOGS,
|
||||
payload: evalPropertyErrors,
|
||||
});
|
||||
}
|
||||
|
||||
errors.forEach((error) => {
|
||||
|
|
@ -260,13 +232,13 @@ export function* logSuccessfulBindings(
|
|||
);
|
||||
const entity = dataTree[entityName];
|
||||
if (isAction(entity) || isWidget(entity)) {
|
||||
const unevalValue = _.get(unEvalTree, evaluatedPath);
|
||||
const unevalValue = get(unEvalTree, evaluatedPath);
|
||||
const entityType = isAction(entity) ? entity.pluginType : entity.type;
|
||||
const isABinding = _.find(entity.dynamicBindingPathList, {
|
||||
const isABinding = find(entity.dynamicBindingPathList, {
|
||||
key: propertyPath,
|
||||
});
|
||||
const logBlackList = entity.logBlackList;
|
||||
const errors: EvaluationError[] = _.get(
|
||||
const errors: EvaluationError[] = get(
|
||||
dataTree,
|
||||
getEvalErrorPath(evaluatedPath),
|
||||
[],
|
||||
|
|
@ -310,7 +282,7 @@ export function* updateTernDefinitions(
|
|||
shouldUpdate = false;
|
||||
} else {
|
||||
// Only when new field is added or deleted, we want to re create the def
|
||||
shouldUpdate = _.some(updates, (update) => {
|
||||
shouldUpdate = some(updates, (update) => {
|
||||
return (
|
||||
update.event === DataTreeDiffEvent.NEW ||
|
||||
update.event === DataTreeDiffEvent.DELETE
|
||||
|
|
|
|||
|
|
@ -545,6 +545,9 @@ export function* deleteAllSelectedWidgetsSaga(
|
|||
type: ENTITY_TYPE.WIDGET,
|
||||
id: widget.widgetId,
|
||||
},
|
||||
analytics: {
|
||||
widgetType: widget.type,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -666,6 +669,9 @@ export function* deleteSaga(deleteAction: ReduxAction<WidgetDelete>) {
|
|||
type: ENTITY_TYPE.WIDGET,
|
||||
id: widget.widgetId,
|
||||
},
|
||||
analytics: {
|
||||
widgetType: widget.type,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,6 +129,8 @@ export type EventName =
|
|||
| "SLASH_COMMAND"
|
||||
| "DEBUGGER_NEW_ERROR"
|
||||
| "DEBUGGER_RESOLVED_ERROR"
|
||||
| "DEBUGGER_NEW_ERROR_MESSAGE"
|
||||
| "DEBUGGER_RESOLVED_ERROR_MESSAGE"
|
||||
| "ADD_MOCK_DATASOURCE_CLICK"
|
||||
| "CREATE_DATA_SOURCE_AUTH_API_CLICK"
|
||||
| "GEN_CRUD_PAGE_CREATE_NEW_DATASOURCE"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,19 @@
|
|||
import { debuggerLogInit } from "actions/debuggerActions";
|
||||
import { Message, Severity, LogActionPayload } from "entities/AppsmithConsole";
|
||||
import {
|
||||
addErrorLogInit,
|
||||
debuggerLogInit,
|
||||
deleteErrorLogInit,
|
||||
} from "actions/debuggerActions";
|
||||
import { ReduxAction } from "constants/ReduxActionConstants";
|
||||
import { Severity, LogActionPayload, Log } from "entities/AppsmithConsole";
|
||||
import moment from "moment";
|
||||
import store from "store";
|
||||
|
||||
function log(ev: Message) {
|
||||
store.dispatch(debuggerLogInit(ev));
|
||||
function dispatchAction(action: ReduxAction<unknown>) {
|
||||
store.dispatch(action);
|
||||
}
|
||||
|
||||
function log(ev: Log) {
|
||||
dispatchAction(debuggerLogInit(ev));
|
||||
}
|
||||
|
||||
function getTimeStamp() {
|
||||
|
|
@ -27,6 +36,9 @@ function warning(ev: LogActionPayload) {
|
|||
});
|
||||
}
|
||||
|
||||
// This is used to show a log as an error
|
||||
// NOTE: These logs won't appear in the errors tab
|
||||
// To add errors to the errors tab use the addError method.
|
||||
function error(ev: LogActionPayload) {
|
||||
log({
|
||||
...ev,
|
||||
|
|
@ -35,8 +47,26 @@ function error(ev: LogActionPayload) {
|
|||
});
|
||||
}
|
||||
|
||||
// This is used to add an error to the errors tab
|
||||
function addError(payload: LogActionPayload) {
|
||||
dispatchAction(
|
||||
addErrorLogInit({
|
||||
...payload,
|
||||
severity: Severity.ERROR,
|
||||
timestamp: getTimeStamp(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// This is used to remove an error from the errors tab
|
||||
function deleteError(id: string, analytics?: Log["analytics"]) {
|
||||
dispatchAction(deleteErrorLogInit(id, analytics));
|
||||
}
|
||||
|
||||
export default {
|
||||
info,
|
||||
warning,
|
||||
error,
|
||||
addError,
|
||||
deleteError,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ import {
|
|||
isPermitted,
|
||||
PERMISSION_TYPE,
|
||||
} from "pages/Applications/permissionHelpers";
|
||||
import { User } from "constants/userConstants";
|
||||
import { getAppsmithConfigs } from "configs";
|
||||
|
||||
const { intercomAppID } = getAppsmithConfigs();
|
||||
|
||||
export const snapToGrid = (
|
||||
columnWidth: number,
|
||||
|
|
@ -397,3 +401,14 @@ export const getIsSafeRedirectURL = (redirectURL: string) => {
|
|||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export function bootIntercom(user?: User) {
|
||||
if (intercomAppID && window.Intercom) {
|
||||
window.Intercom("boot", {
|
||||
app_id: intercomAppID,
|
||||
user_id: user?.username,
|
||||
name: user?.name,
|
||||
email: user?.email,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user