fix: Remove guided tour code (#30387)
## Description Removed the guided tour code. #### PR fixes following issue(s) Fixes https://github.com/appsmithorg/appsmith/issues/30332 #### Type of change - Bug fix (non-breaking change which fixes an issue) - Chore (housekeeping or task changes that don't impact user perception) ## Testing > #### How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration. > Delete anything that is not relevant - [ ] Manual - [ ] JUnit - [ ] Jest - [ ] Cypress > > #### Test Plan > Add Testsmith test cases links that relate to this PR > > #### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) > > > ## Checklist: #### Dev activity - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Chores** - Streamlined onboarding process by removing guided tour features. - Refined action and message management for a more intuitive user experience. - Enhanced property controls generation for better user interaction. - **Refactor** - Simplified various components by removing unnecessary guided tour logic. - Improved application and page sagas for more efficient operation. - Refined editor components for a smoother user interface. - **Documentation** - Updated message constants for clearer user guidance. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
85bd78674c
commit
ced4ffa179
|
|
@ -1,15 +1,5 @@
|
|||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
import type { SIGNPOSTING_STEP } from "pages/Editor/FirstTimeUserOnboarding/Utils";
|
||||
import type { GUIDED_TOUR_STEPS } from "pages/Editor/GuidedTour/constants";
|
||||
import type { GuidedTourState } from "reducers/uiReducers/guidedTourReducer";
|
||||
import type { WidgetProps } from "widgets/BaseWidget";
|
||||
|
||||
export const enableGuidedTour = (payload: boolean) => {
|
||||
return {
|
||||
type: ReduxActionTypes.ENABLE_GUIDED_TOUR,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export const toggleInOnboardingWidgetSelection = (payload: boolean) => {
|
||||
return {
|
||||
|
|
@ -103,129 +93,12 @@ export const showAnonymousDataPopup = (payload: boolean) => {
|
|||
};
|
||||
};
|
||||
|
||||
export const markStepComplete = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.GUIDED_TOUR_MARK_STEP_COMPLETED,
|
||||
};
|
||||
};
|
||||
|
||||
export const tableWidgetWasSelected = (payload: boolean) => {
|
||||
return {
|
||||
type: ReduxActionTypes.TABLE_WIDGET_WAS_SELECTED,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export const setCurrentStepInit = (payload: GUIDED_TOUR_STEPS) => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_CURRENT_STEP_INIT,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export const setCurrentStep = (payload: GUIDED_TOUR_STEPS) => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_CURRENT_STEP,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export const addOnboardingWidget = (payload: Partial<WidgetProps>) => {
|
||||
return {
|
||||
type: ReduxActionTypes.GUIDED_TOUR_ADD_WIDGET,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export const setUpTourApp = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_UP_TOUR_APP,
|
||||
};
|
||||
};
|
||||
|
||||
export const toggleLoader = (payload: boolean) => {
|
||||
return {
|
||||
type: ReduxActionTypes.GUIDED_TOUR_TOGGLE_LOADER,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export const toggleShowDeviationDialog = (payload: boolean) => {
|
||||
return {
|
||||
type: ReduxActionTypes.TOGGLE_DEVIATION_DIALOG,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export const toggleShowEndTourDialog = (payload: boolean) => {
|
||||
return {
|
||||
type: ReduxActionTypes.TOGGLE_END_GUIDED_TOUR_DIALOG,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export const showPostCompletionMessage = (payload: boolean) => {
|
||||
return {
|
||||
type: ReduxActionTypes.TOGGLE_END_GUIDED_TOUR_DIALOG,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export const forceShowContent = (payload: GUIDED_TOUR_STEPS) => {
|
||||
return {
|
||||
type: ReduxActionTypes.FORCE_SHOW_CONTENT,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export const updateButtonWidgetText = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.UPDATE_BUTTON_WIDGET_TEXT,
|
||||
};
|
||||
};
|
||||
|
||||
export const showInfoMessage = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.SHOW_INFO_MESSAGE,
|
||||
};
|
||||
};
|
||||
|
||||
export const focusWidget = (widgetName: string, propertyName?: string) => {
|
||||
return {
|
||||
type: ReduxActionTypes.GUIDED_TOUR_FOCUS_WIDGET,
|
||||
payload: {
|
||||
widgetName,
|
||||
propertyName,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const focusWidgetProperty = (widgetName: string) => {
|
||||
return {
|
||||
type: ReduxActionTypes.FOCUS_WIDGET_PROPERTY,
|
||||
payload: widgetName,
|
||||
};
|
||||
};
|
||||
|
||||
export const onboardingCreateApplication = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.ONBOARDING_CREATE_APPLICATION,
|
||||
};
|
||||
};
|
||||
|
||||
export const loadGuidedTourInit = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.LOAD_GUIDED_TOUR_INIT,
|
||||
};
|
||||
};
|
||||
|
||||
export const loadGuidedTour = (guidedTourState: GuidedTourState) => {
|
||||
return {
|
||||
type: ReduxActionTypes.LOAD_GUIDED_TOUR,
|
||||
payload: guidedTourState,
|
||||
};
|
||||
};
|
||||
|
||||
export const setCurrentApplicationIdForCreateNewApp = (
|
||||
applicationId: string,
|
||||
) => {
|
||||
|
|
@ -241,13 +114,6 @@ export const resetCurrentApplicationIdForCreateNewApp = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const setCurrentPluginIdForCreateNewApp = (pluginId: string) => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_CURRENT_PLUGIN_ID_FOR_CREATE_NEW_APP,
|
||||
payload: pluginId,
|
||||
};
|
||||
};
|
||||
|
||||
export const resetCurrentPluginIdForCreateNewApp = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.RESET_CURRENT_PLUGIN_ID_FOR_CREATE_NEW_APP,
|
||||
|
|
|
|||
|
|
@ -275,9 +275,6 @@ const ActionTypes = {
|
|||
CANCEL_ACTION_MODAL: "CANCEL_ACTION_MODAL",
|
||||
CONFIRM_ACTION_MODAL: "CONFIRM_ACTION_MODAL",
|
||||
CREATE_QUERY_INIT: "CREATE_QUERY_INIT",
|
||||
ONBOARDING_CREATE_APPLICATION: "ONBOARDING_CREATE_APPLICATION",
|
||||
LOAD_GUIDED_TOUR: "LOAD_GUIDED_TOUR",
|
||||
LOAD_GUIDED_TOUR_INIT: "LOAD_GUIDED_TOUR_INIT",
|
||||
SET_IS_RECONNECTING_DATASOURCES_MODAL_OPEN:
|
||||
"SET_IS_RECONNECTING_DATASOURCES_MODAL_OPEN",
|
||||
FETCH_DATASOURCES_INIT: "FETCH_DATASOURCES_INIT",
|
||||
|
|
@ -662,23 +659,9 @@ const ActionTypes = {
|
|||
TOGGLE_FUNCTION_EXECUTE_ON_LOAD_SUCCESS:
|
||||
"TOGGLE_FUNCTION_EXECUTE_ON_LOAD_SUCCESS",
|
||||
SET_JS_ACTION_TO_EXECUTE_ON_PAGELOAD: "SET_JS_ACTION_TO_EXECUTE_ON_PAGELOAD",
|
||||
ENABLE_GUIDED_TOUR: "ENABLE_GUIDED_TOUR",
|
||||
GUIDED_TOUR_MARK_STEP_COMPLETED: "GUIDED_TOUR_MARK_STEP_COMPLETED",
|
||||
SET_CURRENT_STEP: "SET_CURRENT_STEP",
|
||||
SET_CURRENT_STEP_INIT: "SET_CURRENT_STEP_INIT",
|
||||
GUIDED_TOUR_ADD_WIDGET: "GUIDED_TOUR_ADD_WIDGET",
|
||||
TABLE_WIDGET_WAS_SELECTED: "TABLE_WIDGET_WAS_SELECTED",
|
||||
SET_UP_TOUR_APP: "SET_UP_TOUR_APP",
|
||||
GUIDED_TOUR_TOGGLE_LOADER: "GUIDED_TOUR_TOGGLE_LOADER",
|
||||
TOGGLE_DEVIATION_DIALOG: "TOGGLE_DEVIATION_DIALOG",
|
||||
TOGGLE_END_GUIDED_TOUR_DIALOG: "TOGGLE_END_GUIDED_TOUR_DIALOG",
|
||||
SHOW_POST_COMPLETION_MESSAGE: "SHOW_POST_COMPLETION_MESSAGE",
|
||||
GUIDED_TOUR_FOCUS_WIDGET: "GUIDED_TOUR_FOCUS_WIDGET",
|
||||
GUIDED_TOUR_SET_DATASOURCE_ID: "GUIDED_TOUR_SET_DATASOURCE_ID",
|
||||
FOCUS_WIDGET_PROPERTY: "FOCUS_WIDGET_PROPERTY",
|
||||
SHOW_INFO_MESSAGE: "SHOW_INFO_MESSAGE",
|
||||
FORCE_SHOW_CONTENT: "FORCE_SHOW_CONTENT",
|
||||
UPDATE_BUTTON_WIDGET_TEXT: "UPDATE_BUTTON_WIDGET_TEXT",
|
||||
UPDATE_REPLAY_ENTITY: "UPDATE_REPLAY_ENTITY",
|
||||
DELETE_WORKSPACE_INIT: "DELETE_WORKSPACE_INIT",
|
||||
DELETE_WORKSPACE_SUCCESS: "DELETE_WORKSPACE_SUCCESS",
|
||||
|
|
|
|||
|
|
@ -1656,12 +1656,9 @@ export const CONTINUE = () => "Continue";
|
|||
export const PROCEED_TO_NEXT_STEP = () => "Proceed to next step";
|
||||
export const PROCEED = () => "Proceed";
|
||||
export const COMPLETE = () => "Complete";
|
||||
// -- Modal --
|
||||
export const DEVIATION = () => "You are deviating from the tutorial";
|
||||
export const END_CONFIRMATION = () => "Are you sure you want to end?";
|
||||
export const CANCEL_DIALOG = () => "Cancel";
|
||||
// -- End Tutorial --
|
||||
export const END_TUTORIAL = () => "End tutorial";
|
||||
export const CANCEL_DIALOG = () => "Cancel";
|
||||
// -- Intro content --
|
||||
export const TITLE = () =>
|
||||
"In this tutorial we’ll build a tool to display customer information";
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ import type { AppThemingState } from "reducers/uiReducers/appThemingReducer";
|
|||
import type { MainCanvasReduxState } from "reducers/uiReducers/mainCanvasReducer";
|
||||
import type { SettingsReduxState } from "@appsmith/reducers/settingsReducer";
|
||||
import SettingsReducer from "@appsmith/reducers/settingsReducer";
|
||||
import type { GuidedTourState } from "reducers/uiReducers/guidedTourReducer";
|
||||
import type { TriggerValuesEvaluationState } from "reducers/evaluationReducers/triggerReducer";
|
||||
import type { CanvasWidgetStructure } from "WidgetProvider/constants";
|
||||
import type { AppSettingsPaneReduxState } from "reducers/uiReducers/appSettingsPaneReducer";
|
||||
|
|
@ -119,7 +118,6 @@ export interface AppState {
|
|||
datasourceName: DatasourceNameReduxState;
|
||||
theme: ThemeState;
|
||||
onBoarding: OnboardingState;
|
||||
guidedTour: GuidedTourState;
|
||||
globalSearch: GlobalSearchReduxState;
|
||||
releases: ReleasesState;
|
||||
websocket: WebsocketReducerState;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ import appThemingReducer from "reducers/uiReducers/appThemingReducer";
|
|||
import mainCanvasReducer from "reducers/uiReducers/mainCanvasReducer";
|
||||
import focusHistoryReducer from "reducers/uiReducers/focusHistoryReducer";
|
||||
import { editorContextReducer } from "@appsmith/reducers/uiReducers/editorContextReducer";
|
||||
import guidedTourReducer from "reducers/uiReducers/guidedTourReducer";
|
||||
import libraryReducer from "reducers/uiReducers/libraryReducer";
|
||||
import appSettingsPaneReducer from "reducers/uiReducers/appSettingsPaneReducer";
|
||||
import autoHeightUIReducer from "reducers/uiReducers/autoHeightReducer";
|
||||
|
|
@ -76,7 +75,6 @@ export const uiReducerObject = {
|
|||
theme: themeReducer,
|
||||
modalAction: modalActionReducer,
|
||||
onBoarding: onBoardingReducer,
|
||||
guidedTour: guidedTourReducer,
|
||||
globalSearch: globalSearchReducer,
|
||||
releases: releasesReducer,
|
||||
websocket: websocketReducer,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ import {
|
|||
import {
|
||||
deleteRecentAppEntities,
|
||||
getEnableStartSignposting,
|
||||
setPostWelcomeTourState,
|
||||
} from "utils/storage";
|
||||
import {
|
||||
reconnectAppLevelWebsocket,
|
||||
|
|
@ -94,7 +93,6 @@ import {
|
|||
getCurrentWorkspaceId,
|
||||
} from "@appsmith/selectors/workspaceSelectors";
|
||||
|
||||
import { getCurrentStep, inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import { fetchPluginFormConfigs, fetchPlugins } from "actions/pluginActions";
|
||||
import {
|
||||
fetchDatasources,
|
||||
|
|
@ -102,7 +100,6 @@ import {
|
|||
} from "actions/datasourceActions";
|
||||
import { failFastApiCalls } from "sagas/InitSagas";
|
||||
import type { Datasource } from "entities/Datasource";
|
||||
import { GUIDED_TOUR_STEPS } from "pages/Editor/GuidedTour/constants";
|
||||
import { builderURL, viewerURL } from "@appsmith/RouteBuilder";
|
||||
import { getDefaultPageId as selectDefaultPageId } from "sagas/selectors";
|
||||
import PageApi from "api/PageApi";
|
||||
|
|
@ -169,16 +166,10 @@ export function* publishApplicationSaga(
|
|||
|
||||
const applicationId: string = yield select(getCurrentApplicationId);
|
||||
const currentPageId: string = yield select(getCurrentPageId);
|
||||
const guidedTour: boolean = yield select(inGuidedTour);
|
||||
const currentStep: number = yield select(getCurrentStep);
|
||||
|
||||
let appicationViewPageUrl = viewerURL({
|
||||
const appicationViewPageUrl = viewerURL({
|
||||
pageId: currentPageId,
|
||||
});
|
||||
if (guidedTour && currentStep === GUIDED_TOUR_STEPS.DEPLOY) {
|
||||
appicationViewPageUrl += "?&guidedTourComplete=true";
|
||||
yield call(setPostWelcomeTourState, true);
|
||||
}
|
||||
|
||||
yield put(
|
||||
fetchApplication({
|
||||
|
|
@ -868,9 +859,6 @@ export function* importApplicationSaga(
|
|||
});
|
||||
}
|
||||
history.push(pageURL);
|
||||
const guidedTour: boolean = yield select(inGuidedTour);
|
||||
|
||||
if (guidedTour) return;
|
||||
|
||||
toast.show("Application imported successfully", {
|
||||
kind: "success",
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ import DEFAULT_TEMPLATE from "templates/default";
|
|||
import { getAppMode } from "@appsmith/selectors/applicationSelectors";
|
||||
import { setCrudInfoModalData } from "actions/crudInfoModalActions";
|
||||
import { selectWidgetInitAction } from "actions/widgetSelectionActions";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import {
|
||||
fetchJSCollectionsForPage,
|
||||
fetchJSCollectionsForPageError,
|
||||
|
|
@ -114,7 +113,6 @@ import {
|
|||
} from "actions/jsActionActions";
|
||||
|
||||
import WidgetFactory from "WidgetProvider/factory";
|
||||
import { toggleShowDeviationDialog } from "actions/onboardingActions";
|
||||
import { builderURL } from "@appsmith/RouteBuilder";
|
||||
import { failFastApiCalls, waitForWidgetConfigBuild } from "sagas/InitSagas";
|
||||
import { resizePublishedMainCanvasToLowestWidget } from "sagas/WidgetOperationUtils";
|
||||
|
|
@ -529,7 +527,6 @@ export function* savePageSaga(action: ReduxAction<{ isRetry?: boolean }>) {
|
|||
|
||||
if (!editorConfigs) return;
|
||||
|
||||
const guidedTourEnabled: boolean = yield select(inGuidedTour);
|
||||
const savePageRequest: SavePageRequest = getLayoutSavePayload(
|
||||
widgets,
|
||||
editorConfigs,
|
||||
|
|
@ -575,7 +572,7 @@ export function* savePageSaga(action: ReduxAction<{ isRetry?: boolean }>) {
|
|||
const { actionUpdates, messages } = savePageResponse.data;
|
||||
// We do not want to show these toasts in guided tour
|
||||
// Show toast messages from the server
|
||||
if (messages && messages.length && !guidedTourEnabled) {
|
||||
if (messages && messages.length) {
|
||||
savePageResponse.data.messages.forEach((message) => {
|
||||
toast.show(message, {
|
||||
kind: "info",
|
||||
|
|
@ -791,7 +788,6 @@ export function* createPageSaga(
|
|||
createPageAction: ReduxAction<CreatePageActionPayload>,
|
||||
) {
|
||||
try {
|
||||
const guidedTourEnabled: boolean = yield select(inGuidedTour);
|
||||
const layoutSystemType: LayoutSystemTypes =
|
||||
yield select(getLayoutSystemType);
|
||||
const mainCanvasProps: MainCanvasReduxState =
|
||||
|
|
@ -801,11 +797,6 @@ export function* createPageSaga(
|
|||
mainCanvasProps.width,
|
||||
);
|
||||
|
||||
// Prevent user from creating a new page during the guided tour
|
||||
if (guidedTourEnabled) {
|
||||
yield put(toggleShowDeviationDialog(true));
|
||||
return;
|
||||
}
|
||||
const request: CreatePageRequest = createPageAction.payload;
|
||||
const response: FetchPageResponse = yield call(PageApi.createPage, request);
|
||||
const isValidResponse: boolean = yield validateResponse(response);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ function ActionNameEditor(props: ActionNameEditorProps) {
|
|||
|
||||
return (
|
||||
<NameEditorComponent
|
||||
checkForGuidedTour
|
||||
/**
|
||||
* This component is used by module editor in EE which uses a different
|
||||
* action to save the name of an action. The current callers of this component
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import type { FeatureParams } from "./walkthroughContext";
|
|||
import { DEFAULT_DELAY } from "./walkthroughContext";
|
||||
import WalkthroughContext from "./walkthroughContext";
|
||||
import { createPortal } from "react-dom";
|
||||
import { hideIndicator } from "pages/Editor/GuidedTour/utils";
|
||||
import { retryPromise } from "utils/AppsmithUtils";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { isElementVisible } from "./utils";
|
||||
import { hideIndicator } from "components/utils/Indicator";
|
||||
|
||||
const WalkthroughRenderer = lazy(async () => {
|
||||
return retryPromise(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { Icon, Text, Button, Divider } from "design-system";
|
||||
import { showIndicator } from "pages/Editor/GuidedTour/utils";
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import { PADDING_HIGHLIGHT, getPosition } from "./utils";
|
||||
|
|
@ -12,6 +11,7 @@ import WalkthroughContext, {
|
|||
isFeatureFooterDetails,
|
||||
} from "./walkthroughContext";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { showIndicator } from "components/utils/Indicator";
|
||||
|
||||
const CLIPID = "clip__feature";
|
||||
const Z_INDEX = 1000;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
import type { LazyAnimationItem } from "utils/lazyLottie";
|
||||
import lazyLottie from "utils/lazyLottie";
|
||||
import indicatorAnimationURL from "assets/lottie/guided-tour-indicator.json.txt";
|
||||
import { Classes as GuidedTourClasses } from "pages/Editor/GuidedTour/constants";
|
||||
import {
|
||||
setExplorerActiveAction,
|
||||
setExplorerPinnedAction,
|
||||
} from "actions/explorerActions";
|
||||
import log from "loglevel";
|
||||
|
||||
// data-guided-tour-id - used for the rectangular highlight
|
||||
// data-guided-tour-iid - iid(indicator id) used for the lottie animation show near an element
|
||||
|
||||
export const GuidedTourClasses = {
|
||||
GUIDED_TOUR_BORDER: "guided-tour-border",
|
||||
GUIDED_TOUR_SHOW_BORDER: "guided-tour-show-border",
|
||||
GUIDED_TOUR_INDICATOR: "guided-tour-indicator",
|
||||
};
|
||||
|
||||
class IndicatorHelper {
|
||||
timerId!: ReturnType<typeof setTimeout>;
|
||||
indicatorWrapper!: HTMLDivElement;
|
||||
|
|
@ -262,7 +263,3 @@ export function showIndicator(
|
|||
export function hideIndicator() {
|
||||
indicatorHelperInstance.destroy();
|
||||
}
|
||||
|
||||
export function closeSidebar() {
|
||||
return [setExplorerPinnedAction(false), setExplorerActiveAction(false)];
|
||||
}
|
||||
|
|
@ -3,8 +3,6 @@ import { useSelector, useDispatch, shallowEqual } from "react-redux";
|
|||
import { isNameValid } from "utils/helpers";
|
||||
import type { AppState } from "@appsmith/reducers";
|
||||
import log from "loglevel";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import { toggleShowDeviationDialog } from "actions/onboardingActions";
|
||||
import { getUsedActionNames } from "selectors/actionSelectors";
|
||||
import {
|
||||
ACTION_INVALID_NAME_ERROR,
|
||||
|
|
@ -53,7 +51,6 @@ export const IconBox = styled.div`
|
|||
`;
|
||||
|
||||
interface NameEditorProps {
|
||||
checkForGuidedTour?: boolean;
|
||||
children: (params: any) => JSX.Element;
|
||||
id?: string;
|
||||
name?: string;
|
||||
|
|
@ -72,7 +69,6 @@ interface NameEditorProps {
|
|||
|
||||
function NameEditor(props: NameEditorProps) {
|
||||
const {
|
||||
checkForGuidedTour,
|
||||
dispatchAction,
|
||||
id: entityId,
|
||||
idUndefinedErrorMessage,
|
||||
|
|
@ -87,7 +83,6 @@ function NameEditor(props: NameEditorProps) {
|
|||
if (!entityId) {
|
||||
log.error(idUndefinedErrorMessage);
|
||||
}
|
||||
const guidedTourEnabled = useSelector(inGuidedTour);
|
||||
|
||||
const conflictingNames = useSelector(
|
||||
(state: AppState) => getUsedActionNames(state, entityId || ""),
|
||||
|
|
@ -114,15 +109,10 @@ function NameEditor(props: NameEditorProps) {
|
|||
const handleNameChange = useCallback(
|
||||
(name: string) => {
|
||||
if (name !== entityName && !isInvalidNameForEntity(name)) {
|
||||
if (checkForGuidedTour && guidedTourEnabled) {
|
||||
dispatch(toggleShowDeviationDialog(true));
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(dispatchAction({ id: entityId, name }));
|
||||
}
|
||||
},
|
||||
[dispatch, isInvalidNameForEntity, guidedTourEnabled, entityId, entityName],
|
||||
[dispatch, isInvalidNameForEntity, entityId, entityName],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import {
|
|||
} from "actions/gitSyncActions";
|
||||
import { restoreRecentEntitiesRequest } from "actions/globalSearchActions";
|
||||
import { resetEditorSuccess } from "actions/initActions";
|
||||
import { loadGuidedTourInit } from "actions/onboardingActions";
|
||||
import { fetchAllPageEntityCompletion, setupPage } from "actions/pageActions";
|
||||
import {
|
||||
executePageLoadActions,
|
||||
|
|
@ -241,7 +240,6 @@ export default class AppEditorEngine extends AppEngine {
|
|||
currentTabs,
|
||||
});
|
||||
}
|
||||
yield put(loadGuidedTourInit());
|
||||
if (isFirstTimeUserOnboardingComplete) {
|
||||
yield put({
|
||||
type: ReduxActionTypes.SET_FIRST_TIME_USER_ONBOARDING_APPLICATION_IDS,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { createGlobalStyle } from "styled-components";
|
|||
import { Layers } from "constants/Layers";
|
||||
import { Classes } from "@blueprintjs/core";
|
||||
import { Classes as GitSyncClasses } from "pages/Editor/gitSync/constants";
|
||||
import { Classes as GuidedTourClasses } from "pages/Editor/GuidedTour/constants";
|
||||
import { Colors } from "constants/Colors";
|
||||
import { GuidedTourClasses } from "components/utils/Indicator";
|
||||
|
||||
export const replayHighlightClass = "ur--has-border";
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import { getThemeDetails, ThemeMode } from "selectors/themeSelectors";
|
|||
import HtmlTitle from "../AppViewerHtmlTitle";
|
||||
import { NAVIGATION_SETTINGS } from "constants/AppConstants";
|
||||
import PageMenu from "pages/AppViewer/PageMenu";
|
||||
import TourCompletionMessage from "pages/Editor/GuidedTour/TourCompletionMessage";
|
||||
import { useHref } from "pages/Editor/utils";
|
||||
import { builderURL } from "@appsmith/RouteBuilder";
|
||||
import TopHeader from "./components/TopHeader";
|
||||
|
|
@ -137,8 +136,6 @@ export function Navigation() {
|
|||
setMenuOpen={setMenuOpen}
|
||||
url={editorURL}
|
||||
/>
|
||||
|
||||
<TourCompletionMessage />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import { getSelectedAppTheme } from "selectors/appThemingSelectors";
|
|||
import { useSelector } from "react-redux";
|
||||
import BrandingBadge from "./BrandingBadge";
|
||||
import { setAppViewHeaderHeight } from "actions/appViewActions";
|
||||
import { showPostCompletionMessage } from "selectors/onboardingSelectors";
|
||||
import { CANVAS_SELECTOR } from "constants/WidgetConstants";
|
||||
import { setupPublishedPage } from "actions/pageActions";
|
||||
import usePrevious from "utils/hooks/usePrevious";
|
||||
|
|
@ -56,7 +55,6 @@ import { getHideWatermark } from "@appsmith/selectors/tenantSelectors";
|
|||
const AppViewerBody = styled.section<{
|
||||
hasPages: boolean;
|
||||
headerHeight: number;
|
||||
showGuidedTourMessage: boolean;
|
||||
}>`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
@ -92,7 +90,6 @@ function AppViewer(props: Props) {
|
|||
const lightTheme = useSelector((state: AppState) =>
|
||||
getThemeDetails(state, ThemeMode.LIGHT),
|
||||
);
|
||||
const showGuidedTourMessage = useSelector(showPostCompletionMessage);
|
||||
const headerHeight = useSelector(getAppViewHeaderHeight);
|
||||
const branch = getSearchQuery(search, GIT_BRANCH_QUERY_KEY);
|
||||
const prevValues = usePrevious({ branch, location: props.location, pageId });
|
||||
|
|
@ -219,7 +216,6 @@ function AppViewer(props: Props) {
|
|||
hasPages={pages.length > 1}
|
||||
headerHeight={headerHeight}
|
||||
ref={focusRef}
|
||||
showGuidedTourMessage={showGuidedTourMessage}
|
||||
>
|
||||
{isInitialized && <AppViewerPageContainer />}
|
||||
</AppViewerBody>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import {
|
|||
datasourcesEditorIdURL,
|
||||
saasEditorDatasourceIdURL,
|
||||
} from "@appsmith/RouteBuilder";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { useLocation } from "react-router";
|
||||
import omit from "lodash/omit";
|
||||
|
|
@ -57,7 +56,6 @@ const DataStructureListWrapper = styled.div<{ height: number }>`
|
|||
const ExplorerDatasourceEntity = React.memo(
|
||||
(props: ExplorerDatasourceEntityProps) => {
|
||||
const { entityId } = props;
|
||||
const guidedTourEnabled = useSelector(inGuidedTour);
|
||||
const dispatch = useDispatch();
|
||||
const icon = getPluginIcon(props.plugin);
|
||||
const location = useLocation();
|
||||
|
|
@ -152,10 +150,6 @@ const ExplorerDatasourceEntity = React.memo(
|
|||
} else if (queryAction && isStoredDatasource(queryAction.datasource)) {
|
||||
isDefaultExpanded = queryAction.datasource.id === props.datasource.id;
|
||||
}
|
||||
// In guided tour we want the datasource structure to be shown only when expanded
|
||||
if (guidedTourEnabled) {
|
||||
isDefaultExpanded = false;
|
||||
}
|
||||
|
||||
return (
|
||||
<Entity
|
||||
|
|
|
|||
|
|
@ -62,9 +62,6 @@ import {
|
|||
COMMUNITY_TEMPLATES,
|
||||
APPLICATION_INVITE,
|
||||
} from "@appsmith/constants/messages";
|
||||
import Boxed from "./GuidedTour/Boxed";
|
||||
import EndTour from "./GuidedTour/EndTour";
|
||||
import { GUIDED_TOUR_STEPS } from "./GuidedTour/constants";
|
||||
import { viewerURL } from "@appsmith/RouteBuilder";
|
||||
import { useHref } from "./utils";
|
||||
import { getAppsmithConfigs } from "@appsmith/configs";
|
||||
|
|
@ -254,98 +251,93 @@ export function EditorHeader() {
|
|||
<HelperBarInHeader />
|
||||
|
||||
<HeaderSection className="gap-x-1">
|
||||
<Boxed
|
||||
alternative={<EndTour />}
|
||||
step={GUIDED_TOUR_STEPS.BUTTON_ONSUCCESS_BINDING}
|
||||
<RealtimeAppEditors applicationId={applicationId} />
|
||||
<ToggleModeButton />
|
||||
{applicationId && <EditorShareButton setShowModal={setShowModal} />}
|
||||
<Modal
|
||||
onOpenChange={(isOpen) => setShowModal(isOpen)}
|
||||
open={showModal}
|
||||
>
|
||||
<RealtimeAppEditors applicationId={applicationId} />
|
||||
<ToggleModeButton />
|
||||
{applicationId && <EditorShareButton setShowModal={setShowModal} />}
|
||||
<Modal
|
||||
onOpenChange={(isOpen) => setShowModal(isOpen)}
|
||||
open={showModal}
|
||||
>
|
||||
<ModalContent style={{ width: "640px" }}>
|
||||
<ModalHeader>
|
||||
{createMessage(
|
||||
APPLICATION_INVITE,
|
||||
currentWorkspace.name,
|
||||
!isGACEnabled,
|
||||
)}
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<Tabs
|
||||
onValueChange={(value) => setActiveTab(value)}
|
||||
value={activeTab}
|
||||
>
|
||||
<TabsList>
|
||||
<Tab data-testid="t--tab-INVITE" value="invite">
|
||||
{createMessage(INVITE_TAB)}
|
||||
</Tab>
|
||||
<Tab data-testid="t--tab-EMBED" value="embed">
|
||||
{createMessage(IN_APP_EMBED_SETTING.embed)}
|
||||
</Tab>
|
||||
{featureFlags.release_show_publish_app_to_community_enabled &&
|
||||
cloudHosting && (
|
||||
<Tab data-testid="t--tab-PUBLISH" value="publish">
|
||||
{createMessage(COMMUNITY_TEMPLATES.tabTitle)}
|
||||
</Tab>
|
||||
)}
|
||||
</TabsList>
|
||||
<TabPanel value="invite">
|
||||
<AppInviteUsersForm
|
||||
applicationId={applicationId}
|
||||
workspaceId={workspaceId}
|
||||
<ModalContent style={{ width: "640px" }}>
|
||||
<ModalHeader>
|
||||
{createMessage(
|
||||
APPLICATION_INVITE,
|
||||
currentWorkspace.name,
|
||||
!isGACEnabled,
|
||||
)}
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<Tabs
|
||||
onValueChange={(value) => setActiveTab(value)}
|
||||
value={activeTab}
|
||||
>
|
||||
<TabsList>
|
||||
<Tab data-testid="t--tab-INVITE" value="invite">
|
||||
{createMessage(INVITE_TAB)}
|
||||
</Tab>
|
||||
<Tab data-testid="t--tab-EMBED" value="embed">
|
||||
{createMessage(IN_APP_EMBED_SETTING.embed)}
|
||||
</Tab>
|
||||
{featureFlags.release_show_publish_app_to_community_enabled &&
|
||||
cloudHosting && (
|
||||
<Tab data-testid="t--tab-PUBLISH" value="publish">
|
||||
{createMessage(COMMUNITY_TEMPLATES.tabTitle)}
|
||||
</Tab>
|
||||
)}
|
||||
</TabsList>
|
||||
<TabPanel value="invite">
|
||||
<AppInviteUsersForm
|
||||
applicationId={applicationId}
|
||||
workspaceId={workspaceId}
|
||||
/>
|
||||
</TabPanel>
|
||||
<TabPanel value="embed">
|
||||
{getEmbedSnippetForm(isPrivateEmbedEnabled, setActiveTab)}
|
||||
</TabPanel>
|
||||
{cloudHosting && (
|
||||
<TabPanel value="publish">
|
||||
<CommunityTemplatesPublishInfo
|
||||
onPublishClick={() =>
|
||||
setShowPublishCommunityTemplateModal(true)
|
||||
}
|
||||
setShowHostModal={setShowModal}
|
||||
/>
|
||||
</TabPanel>
|
||||
<TabPanel value="embed">
|
||||
{getEmbedSnippetForm(isPrivateEmbedEnabled, setActiveTab)}
|
||||
</TabPanel>
|
||||
{cloudHosting && (
|
||||
<TabPanel value="publish">
|
||||
<CommunityTemplatesPublishInfo
|
||||
onPublishClick={() =>
|
||||
setShowPublishCommunityTemplateModal(true)
|
||||
}
|
||||
setShowHostModal={setShowModal}
|
||||
/>
|
||||
</TabPanel>
|
||||
)}
|
||||
</Tabs>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
<PublishCommunityTemplateModal
|
||||
onPublishSuccess={() => {
|
||||
setShowPublishCommunityTemplateModal(false);
|
||||
setShowModal(true);
|
||||
}}
|
||||
setShowModal={setShowPublishCommunityTemplateModal}
|
||||
showModal={showPublishCommunityTemplateModal}
|
||||
/>
|
||||
<div className="flex items-center">
|
||||
<Tooltip
|
||||
content={createMessage(DEPLOY_BUTTON_TOOLTIP)}
|
||||
placement="bottomRight"
|
||||
)}
|
||||
</Tabs>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
<PublishCommunityTemplateModal
|
||||
onPublishSuccess={() => {
|
||||
setShowPublishCommunityTemplateModal(false);
|
||||
setShowModal(true);
|
||||
}}
|
||||
setShowModal={setShowPublishCommunityTemplateModal}
|
||||
showModal={showPublishCommunityTemplateModal}
|
||||
/>
|
||||
<div className="flex items-center">
|
||||
<Tooltip
|
||||
content={createMessage(DEPLOY_BUTTON_TOOLTIP)}
|
||||
placement="bottomRight"
|
||||
>
|
||||
<Button
|
||||
className="t--application-publish-btn"
|
||||
data-guided-tour-iid="deploy"
|
||||
id={"application-publish-btn"}
|
||||
isDisabled={isProtectedMode}
|
||||
isLoading={isPublishing}
|
||||
kind="tertiary"
|
||||
onClick={() => handleClickDeploy(true)}
|
||||
size="md"
|
||||
startIcon={"rocket"}
|
||||
>
|
||||
<Button
|
||||
className="t--application-publish-btn"
|
||||
data-guided-tour-iid="deploy"
|
||||
id={"application-publish-btn"}
|
||||
isDisabled={isProtectedMode}
|
||||
isLoading={isPublishing}
|
||||
kind="tertiary"
|
||||
onClick={() => handleClickDeploy(true)}
|
||||
size="md"
|
||||
startIcon={"rocket"}
|
||||
>
|
||||
{DEPLOY_MENU_OPTION()}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
{DEPLOY_MENU_OPTION()}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<DeployLinkButtonDialog link={deployLink} trigger="" />
|
||||
</div>
|
||||
</Boxed>
|
||||
<DeployLinkButtonDialog link={deployLink} trigger="" />
|
||||
</div>
|
||||
</HeaderSection>
|
||||
<Omnibar />
|
||||
</HeaderWrapper>
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ import history from "utils/history";
|
|||
import { useNewActionName } from "./helpers";
|
||||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import { toggleShowDeviationDialog } from "actions/onboardingActions";
|
||||
import {
|
||||
CONTEXT_COPY,
|
||||
CONTEXT_DELETE,
|
||||
|
|
@ -49,7 +47,6 @@ export function ActionEntityContextMenu(props: EntityContextMenuProps) {
|
|||
|
||||
const { canDeleteAction, canManageAction } = props;
|
||||
const nextEntityName = useNewActionName();
|
||||
const guidedTourEnabled = useSelector(inGuidedTour);
|
||||
const dispatch = useDispatch();
|
||||
const [confirmDelete, setConfirmDelete] = useState(false);
|
||||
const copyActionToPage = useCallback(
|
||||
|
|
@ -77,14 +74,9 @@ export function ActionEntityContextMenu(props: EntityContextMenuProps) {
|
|||
);
|
||||
const deleteActionFromPage = useCallback(
|
||||
(actionId: string, actionName: string, onSuccess?: () => void) => {
|
||||
if (guidedTourEnabled) {
|
||||
dispatch(toggleShowDeviationDialog(true));
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(deleteAction({ id: actionId, name: actionName, onSuccess }));
|
||||
},
|
||||
[dispatch, guidedTourEnabled],
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const convertQueryToModuleOption = useConvertToModuleOptions({
|
||||
|
|
@ -96,12 +88,8 @@ export function ActionEntityContextMenu(props: EntityContextMenuProps) {
|
|||
const menuPages = useSelector(getPageListAsOptions);
|
||||
|
||||
const editActionName = useCallback(() => {
|
||||
if (guidedTourEnabled) {
|
||||
dispatch(toggleShowDeviationDialog(true));
|
||||
return;
|
||||
}
|
||||
dispatch(initExplorerEntityNameEdit(props.id));
|
||||
}, [dispatch, props.id, guidedTourEnabled]);
|
||||
}, [dispatch, props.id]);
|
||||
|
||||
const showBinding = useCallback(
|
||||
(actionId, actionName) =>
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ import {
|
|||
} from "actions/pluginActionActions";
|
||||
|
||||
import { useNewActionName } from "./helpers";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import { toggleShowDeviationDialog } from "actions/onboardingActions";
|
||||
import {
|
||||
CONTEXT_COPY,
|
||||
CONTEXT_DELETE,
|
||||
|
|
@ -43,7 +41,6 @@ interface EntityContextMenuProps {
|
|||
export function MoreActionsMenu(props: EntityContextMenuProps) {
|
||||
const [isMenuOpen, toggleMenuOpen] = useToggle([false, true]);
|
||||
const nextEntityName = useNewActionName();
|
||||
const guidedTourEnabled = useSelector(inGuidedTour);
|
||||
const [confirmDelete, setConfirmDelete] = useState(false);
|
||||
const { isChangePermitted = false, isDeletePermitted = false } = props;
|
||||
|
||||
|
|
@ -73,14 +70,9 @@ export function MoreActionsMenu(props: EntityContextMenuProps) {
|
|||
);
|
||||
const deleteActionFromPage = useCallback(
|
||||
(actionId: string, actionName: string) => {
|
||||
if (guidedTourEnabled) {
|
||||
dispatch(toggleShowDeviationDialog(true));
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(deleteAction({ id: actionId, name: actionName }));
|
||||
},
|
||||
[dispatch, guidedTourEnabled],
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const menuPages = useSelector((state: AppState) => {
|
||||
|
|
|
|||
|
|
@ -21,10 +21,6 @@ import { noop } from "lodash";
|
|||
import { useDispatch, useSelector } from "react-redux";
|
||||
import useClick from "utils/hooks/useClick";
|
||||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import { toggleShowDeviationDialog } from "actions/onboardingActions";
|
||||
import Boxed from "pages/Editor/GuidedTour/Boxed";
|
||||
import { GUIDED_TOUR_STEPS } from "pages/Editor/GuidedTour/constants";
|
||||
import { getEntityCollapsibleState } from "selectors/editorContextSelectors";
|
||||
import type { AppState } from "@appsmith/reducers";
|
||||
import { setEntityCollapsibleState } from "actions/editorContextActions";
|
||||
|
|
@ -265,7 +261,6 @@ export const Entity = forwardRef(
|
|||
const isUpdating = useEntityUpdateState(props.entityId);
|
||||
const isEditing = useEntityEditState(props.entityId);
|
||||
const dispatch = useDispatch();
|
||||
const guidedTourEnabled = useSelector(inGuidedTour);
|
||||
|
||||
const isOpen =
|
||||
(isEntityOpen === undefined ? isDefaultExpanded : isEntityOpen) ||
|
||||
|
|
@ -317,10 +312,6 @@ export const Entity = forwardRef(
|
|||
|
||||
const enterEditMode = useCallback(() => {
|
||||
if (!canEditEntityName) return;
|
||||
if (guidedTourEnabled) {
|
||||
dispatch(toggleShowDeviationDialog(true));
|
||||
return;
|
||||
}
|
||||
props.updateEntityName &&
|
||||
dispatch({
|
||||
type: ReduxActionTypes.INIT_EXPLORER_ENTITY_NAME_EDIT,
|
||||
|
|
@ -328,7 +319,7 @@ export const Entity = forwardRef(
|
|||
id: props.entityId,
|
||||
},
|
||||
});
|
||||
}, [dispatch, props.entityId, props.updateEntityName, guidedTourEnabled]);
|
||||
}, [dispatch, props.entityId, props.updateEntityName]);
|
||||
|
||||
const itemRef = useRef<HTMLDivElement | null>(null);
|
||||
useClick(itemRef, handleClick, noop);
|
||||
|
|
@ -349,101 +340,96 @@ export const Entity = forwardRef(
|
|||
);
|
||||
|
||||
return (
|
||||
<Boxed
|
||||
show={props.name === "updateCustomerInfo"}
|
||||
step={GUIDED_TOUR_STEPS.BIND_OTHER_FORM_WIDGETS}
|
||||
<Wrapper
|
||||
active={!!props.active}
|
||||
className={`${EntityClassNames.WRAPPER} ${props.className}`}
|
||||
ref={ref}
|
||||
>
|
||||
<Wrapper
|
||||
<EntityItem
|
||||
active={!!props.active}
|
||||
className={`${EntityClassNames.WRAPPER} ${props.className}`}
|
||||
ref={ref}
|
||||
alwaysShowRightIcon={props.alwaysShowRightIcon}
|
||||
className={`${props.highlight ? "highlighted" : ""} ${
|
||||
props.active ? "active" : ""
|
||||
} t--entity-item`}
|
||||
data-guided-tour-id={`explorer-entity-${props.name}`}
|
||||
data-guided-tour-iid={props.name}
|
||||
data-testid={`t--entity-item-${props.name}`}
|
||||
disabled={!!props.disabled}
|
||||
highlight={!!props.highlight}
|
||||
id={"entity-" + props.entityId}
|
||||
isSticky={props.isSticky === true}
|
||||
rightIconClickable={typeof props.onClickRightIcon === "function"}
|
||||
spaced={!!props.children}
|
||||
step={props.step}
|
||||
>
|
||||
<EntityItem
|
||||
active={!!props.active}
|
||||
alwaysShowRightIcon={props.alwaysShowRightIcon}
|
||||
className={`${props.highlight ? "highlighted" : ""} ${
|
||||
props.active ? "active" : ""
|
||||
} t--entity-item`}
|
||||
data-guided-tour-id={`explorer-entity-${props.name}`}
|
||||
data-guided-tour-iid={props.name}
|
||||
data-testid={`t--entity-item-${props.name}`}
|
||||
<CollapseToggle
|
||||
className={`${EntityClassNames.COLLAPSE_TOGGLE}`}
|
||||
disabled={!!props.disabled}
|
||||
highlight={!!props.highlight}
|
||||
id={"entity-" + props.entityId}
|
||||
isSticky={props.isSticky === true}
|
||||
rightIconClickable={typeof props.onClickRightIcon === "function"}
|
||||
spaced={!!props.children}
|
||||
step={props.step}
|
||||
>
|
||||
<CollapseToggle
|
||||
className={`${EntityClassNames.COLLAPSE_TOGGLE}`}
|
||||
disabled={!!props.disabled}
|
||||
isOpen={!!isOpen}
|
||||
isVisible={!!props.children}
|
||||
onClick={toggleChildren}
|
||||
/>
|
||||
<IconWrapper
|
||||
className={`${EntityClassNames.ICON}`}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{props.icon}
|
||||
</IconWrapper>
|
||||
<EntityName
|
||||
className={`${EntityClassNames.NAME}`}
|
||||
enterEditMode={enterEditMode}
|
||||
entityId={props.entityId}
|
||||
exitEditMode={exitEditMode}
|
||||
isBeta={props.isBeta}
|
||||
isEditing={!!props.updateEntityName && isEditing}
|
||||
name={props.name}
|
||||
nameTransformFn={props.onNameEdit}
|
||||
ref={itemRef}
|
||||
searchKeyword={props.searchKeyword}
|
||||
updateEntityName={updateNameCallback}
|
||||
/>
|
||||
{isUpdating && (
|
||||
<SubItemWrapper>
|
||||
<Spinner />
|
||||
</SubItemWrapper>
|
||||
)}
|
||||
{props.isBeta && (
|
||||
<SubItemWrapper>
|
||||
<Tag isClosable={false}>
|
||||
{createMessage(EXPLORER_BETA_ENTITY)}
|
||||
</Tag>
|
||||
</SubItemWrapper>
|
||||
)}
|
||||
{props.preRightIcon && (
|
||||
<IconWrapper
|
||||
className={`${EntityClassNames.PRE_RIGHT_ICON} w-full h-full`}
|
||||
onClick={props.onClickPreRightIcon}
|
||||
>
|
||||
{props.preRightIcon}
|
||||
</IconWrapper>
|
||||
)}
|
||||
{props.rightIcon && (
|
||||
<IconWrapper
|
||||
className={EntityClassNames.RIGHT_ICON}
|
||||
onClick={props.onClickRightIcon}
|
||||
>
|
||||
{props.rightIcon}
|
||||
</IconWrapper>
|
||||
)}
|
||||
{showAddButton && addButton}
|
||||
{props.contextMenu && (
|
||||
<ContextMenuWrapper>{props.contextMenu}</ContextMenuWrapper>
|
||||
)}
|
||||
</EntityItem>
|
||||
<Collapse
|
||||
active={props.active}
|
||||
collapseRef={props.collapseRef}
|
||||
isOpen={!!isOpen}
|
||||
step={props.step}
|
||||
isVisible={!!props.children}
|
||||
onClick={toggleChildren}
|
||||
/>
|
||||
<IconWrapper
|
||||
className={`${EntityClassNames.ICON}`}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{props.children}
|
||||
</Collapse>
|
||||
</Wrapper>
|
||||
</Boxed>
|
||||
{props.icon}
|
||||
</IconWrapper>
|
||||
<EntityName
|
||||
className={`${EntityClassNames.NAME}`}
|
||||
enterEditMode={enterEditMode}
|
||||
entityId={props.entityId}
|
||||
exitEditMode={exitEditMode}
|
||||
isBeta={props.isBeta}
|
||||
isEditing={!!props.updateEntityName && isEditing}
|
||||
name={props.name}
|
||||
nameTransformFn={props.onNameEdit}
|
||||
ref={itemRef}
|
||||
searchKeyword={props.searchKeyword}
|
||||
updateEntityName={updateNameCallback}
|
||||
/>
|
||||
{isUpdating && (
|
||||
<SubItemWrapper>
|
||||
<Spinner />
|
||||
</SubItemWrapper>
|
||||
)}
|
||||
{props.isBeta && (
|
||||
<SubItemWrapper>
|
||||
<Tag isClosable={false}>
|
||||
{createMessage(EXPLORER_BETA_ENTITY)}
|
||||
</Tag>
|
||||
</SubItemWrapper>
|
||||
)}
|
||||
{props.preRightIcon && (
|
||||
<IconWrapper
|
||||
className={`${EntityClassNames.PRE_RIGHT_ICON} w-full h-full`}
|
||||
onClick={props.onClickPreRightIcon}
|
||||
>
|
||||
{props.preRightIcon}
|
||||
</IconWrapper>
|
||||
)}
|
||||
{props.rightIcon && (
|
||||
<IconWrapper
|
||||
className={EntityClassNames.RIGHT_ICON}
|
||||
onClick={props.onClickRightIcon}
|
||||
>
|
||||
{props.rightIcon}
|
||||
</IconWrapper>
|
||||
)}
|
||||
{showAddButton && addButton}
|
||||
{props.contextMenu && (
|
||||
<ContextMenuWrapper>{props.contextMenu}</ContextMenuWrapper>
|
||||
)}
|
||||
</EntityItem>
|
||||
<Collapse
|
||||
active={props.active}
|
||||
collapseRef={props.collapseRef}
|
||||
isOpen={!!isOpen}
|
||||
step={props.step}
|
||||
>
|
||||
{props.children}
|
||||
</Collapse>
|
||||
</Wrapper>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ import {
|
|||
} from "@appsmith/constants/ReduxActionConstants";
|
||||
import WidgetFactory from "WidgetProvider/factory";
|
||||
import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
|
||||
import { toggleShowDeviationDialog } from "actions/onboardingActions";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import type { TreeDropdownOption } from "pages/Editor/Explorer/ContextMenu";
|
||||
import ContextMenu from "pages/Editor/Explorer/ContextMenu";
|
||||
const WidgetTypes = WidgetFactory.widgetTypes;
|
||||
|
|
@ -32,7 +30,6 @@ export function WidgetContextMenu(props: {
|
|||
if (parentId) return state.ui.pageWidgets[props.pageId].dsl[parentId];
|
||||
return {};
|
||||
});
|
||||
const guidedTourEnabled = useSelector(inGuidedTour);
|
||||
const dispatch = useDispatch();
|
||||
const dispatchDelete = useCallback(() => {
|
||||
// If the widget is a tab we are updating the `tabs` of the property of the widget
|
||||
|
|
@ -71,12 +68,8 @@ export function WidgetContextMenu(props: {
|
|||
}, []);
|
||||
|
||||
const editWidgetName = useCallback(() => {
|
||||
if (guidedTourEnabled) {
|
||||
dispatch(toggleShowDeviationDialog(true));
|
||||
return;
|
||||
}
|
||||
dispatch(initExplorerEntityNameEdit(widgetId));
|
||||
}, [dispatch, widgetId, guidedTourEnabled]);
|
||||
}, [dispatch, widgetId]);
|
||||
|
||||
const optionTree: TreeDropdownOption[] = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import {
|
|||
EMPTY_WIDGET_MAIN_TEXT,
|
||||
} from "@appsmith/constants/messages";
|
||||
import { selectWidgetsForCurrentPage } from "@appsmith/selectors/entitiesSelector";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import {
|
||||
getExplorerStatus,
|
||||
saveExplorerStatus,
|
||||
|
|
@ -37,13 +36,9 @@ export const ExplorerWidgetGroup = memo((props: ExplorerWidgetGroupProps) => {
|
|||
const applicationId = useSelector(getCurrentApplicationId);
|
||||
const pageId = useSelector(getCurrentPageId) || "";
|
||||
const widgets = useSelector(selectWidgetsForCurrentPage);
|
||||
const guidedTour = useSelector(inGuidedTour);
|
||||
let isWidgetsOpen = getExplorerStatus(applicationId, "widgets");
|
||||
if (isWidgetsOpen === null || isWidgetsOpen === undefined) {
|
||||
isWidgetsOpen = widgets?.children?.length === 0 || guidedTour;
|
||||
saveExplorerStatus(applicationId, "widgets", isWidgetsOpen);
|
||||
} else if (guidedTour) {
|
||||
isWidgetsOpen = guidedTour;
|
||||
isWidgetsOpen = widgets?.children?.length === 0;
|
||||
saveExplorerStatus(applicationId, "widgets", isWidgetsOpen);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,3 @@
|
|||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
import { APPLICATIONS_URL } from "constants/routes";
|
||||
import type { Dispatch } from "react";
|
||||
import history from "utils/history";
|
||||
|
||||
export const triggerWelcomeTour = (dispatch: Dispatch<any>) => {
|
||||
history.push(APPLICATIONS_URL);
|
||||
dispatch({
|
||||
type: ReduxActionTypes.ONBOARDING_CREATE_APPLICATION,
|
||||
});
|
||||
};
|
||||
|
||||
export enum SIGNPOSTING_STEP {
|
||||
CONNECT_A_DATASOURCE = "CONNECT_A_DATASOURCE",
|
||||
CREATE_A_QUERY = "CREATE_A_QUERY",
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
import React from "react";
|
||||
import type { ReactNode } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import {
|
||||
forceShowContentSelector,
|
||||
getCurrentStep,
|
||||
inGuidedTour,
|
||||
} from "selectors/onboardingSelectors";
|
||||
|
||||
interface BoxedProps {
|
||||
alternative?: JSX.Element;
|
||||
children: ReactNode;
|
||||
step: number;
|
||||
// under which condition do you want to show an alternative or nothing(meaning hide)
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
// Boxed(or hidden).
|
||||
function Boxed(props: BoxedProps): JSX.Element | null {
|
||||
const guidedTour = useSelector(inGuidedTour);
|
||||
const currentStep = useSelector(getCurrentStep);
|
||||
const forceShowContent = useSelector(forceShowContentSelector);
|
||||
|
||||
const hide =
|
||||
guidedTour &&
|
||||
props.show &&
|
||||
forceShowContent < props.step &&
|
||||
currentStep <= props.step;
|
||||
if (hide) {
|
||||
if (props.alternative) {
|
||||
return props.alternative;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
|
||||
Boxed.defaultProps = {
|
||||
show: true,
|
||||
// Some out of bound value as by default the children
|
||||
// of this component is to be hidden
|
||||
step: 99,
|
||||
};
|
||||
|
||||
export default Boxed;
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
import { useSelector } from "react-redux";
|
||||
import {
|
||||
enableGuidedTour,
|
||||
toggleShowDeviationDialog,
|
||||
toggleShowEndTourDialog,
|
||||
} from "actions/onboardingActions";
|
||||
import {
|
||||
Button,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalFooter,
|
||||
} from "design-system";
|
||||
import {
|
||||
CANCEL_DIALOG,
|
||||
createMessage,
|
||||
DEVIATION,
|
||||
END_CONFIRMATION,
|
||||
} from "@appsmith/constants/messages";
|
||||
import React from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import {
|
||||
showDeviatingDialogSelector,
|
||||
showEndTourDialogSelector,
|
||||
} from "selectors/onboardingSelectors";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
|
||||
function GuidedTourDialog() {
|
||||
const showDeviatingDialog = useSelector(showDeviatingDialogSelector);
|
||||
const showEndTourDialog = useSelector(showEndTourDialogSelector);
|
||||
const dispatch = useDispatch();
|
||||
const title = showDeviatingDialog
|
||||
? createMessage(DEVIATION)
|
||||
: createMessage(END_CONFIRMATION);
|
||||
|
||||
const onClose = () => {
|
||||
if (showDeviatingDialog) {
|
||||
dispatch(toggleShowDeviationDialog(false));
|
||||
}
|
||||
if (showEndTourDialog) {
|
||||
dispatch(toggleShowEndTourDialog(false));
|
||||
}
|
||||
};
|
||||
|
||||
const endTour = () => {
|
||||
onClose();
|
||||
dispatch(enableGuidedTour(false));
|
||||
AnalyticsUtil.logEvent("END_GUIDED_TOUR_CLICK");
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
onOpenChange={onClose}
|
||||
open={showEndTourDialog || showDeviatingDialog}
|
||||
>
|
||||
<ModalContent
|
||||
onEscapeKeyDown={(e) => e.preventDefault()}
|
||||
// Don't close Modal when pressed outside
|
||||
onInteractOutside={(e) => e.preventDefault()}
|
||||
style={{ width: "640px" }}
|
||||
>
|
||||
<ModalHeader>{title}</ModalHeader>
|
||||
<ModalBody>
|
||||
You will be able to restart this tutorial at any time by clicking on{" "}
|
||||
<b>Welcome tour</b> at the bottom left of the home page
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
className="cancel"
|
||||
kind="secondary"
|
||||
onClick={onClose}
|
||||
size="md"
|
||||
>
|
||||
{createMessage(CANCEL_DIALOG)}
|
||||
</Button>
|
||||
<Button className="end" onClick={endTour} size="md">
|
||||
{createMessage(END_CONFIRMATION)}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default GuidedTourDialog;
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
import { enableGuidedTour } from "actions/onboardingActions";
|
||||
import { createMessage, END_TUTORIAL } from "@appsmith/constants/messages";
|
||||
import React from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { Button } from "design-system";
|
||||
|
||||
function EndTour() {
|
||||
const dispatch = useDispatch();
|
||||
const endTour = () => {
|
||||
dispatch(enableGuidedTour(false));
|
||||
AnalyticsUtil.logEvent("END_GUIDED_TOUR_CLICK");
|
||||
};
|
||||
|
||||
return (
|
||||
<Button kind="tertiary" onClick={endTour} size="md">
|
||||
{createMessage(END_TUTORIAL)}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export default EndTour;
|
||||
|
|
@ -1,476 +0,0 @@
|
|||
import {
|
||||
setUpTourApp,
|
||||
showInfoMessage,
|
||||
toggleLoader,
|
||||
} from "actions/onboardingActions";
|
||||
import { Button, Icon, Text } from "design-system";
|
||||
import { isArray } from "lodash";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import lazyLottie from "utils/lazyLottie";
|
||||
import tickMarkAnimationURL from "assets/lottie/guided-tour-tick-mark.json.txt";
|
||||
import {
|
||||
getCurrentStep,
|
||||
getQueryAction,
|
||||
isExploringSelector,
|
||||
loading,
|
||||
showInfoMessageSelector,
|
||||
showSuccessMessage,
|
||||
} from "selectors/onboardingSelectors";
|
||||
import { useSelector } from "react-redux";
|
||||
import styled from "styled-components";
|
||||
import { GUIDED_TOUR_STEPS, Steps } from "./constants";
|
||||
import useComputeCurrentStep from "./useComputeCurrentStep";
|
||||
import {
|
||||
BUTTON_TEXT,
|
||||
COMPLETE,
|
||||
CONTINUE,
|
||||
createMessage,
|
||||
DESCRIPTION,
|
||||
PROCEED,
|
||||
PROCEED_TO_NEXT_STEP,
|
||||
TITLE,
|
||||
} from "@appsmith/constants/messages";
|
||||
|
||||
const GuideWrapper = styled.div`
|
||||
user-select: text;
|
||||
`;
|
||||
|
||||
const CardWrapper = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
border-bottom: 1px solid var(--ads-v2-color-border);
|
||||
flex-direction: column;
|
||||
background: var(--ads-v2-color-bg-information);
|
||||
`;
|
||||
|
||||
const TitleWrapper = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const StepCount = styled.div`
|
||||
background: var(--ads-v2-color-bg-emphasis-max);
|
||||
color: var(--ads-v2-color-fg-on-emphasis-plus);
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
border-radius: var(--ads-v2-border-radius-circle);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: var(--ads-v2-spaces-3);
|
||||
`;
|
||||
|
||||
const Description = styled.span<{ addLeftSpacing?: boolean }>`
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
|
||||
padding-left: ${(props) => (props.addLeftSpacing ? `20px` : "0")};
|
||||
margin-top: var(--ads-v2-spaces-2);
|
||||
`;
|
||||
|
||||
const UpperContent = styled.div`
|
||||
padding: var(--ads-v2-spaces-5);
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const ContentWrapper = styled.div`
|
||||
display: flex;
|
||||
gap: 50px;
|
||||
align-items: center;
|
||||
.guided-title {
|
||||
color: var(--ads-v2-color-fg-emphasis);
|
||||
}
|
||||
`;
|
||||
|
||||
const GuideButton = styled(Button)<{ isVisible?: boolean }>`
|
||||
visibility: ${({ isVisible = true }) => (isVisible ? "visible" : "hidden")};
|
||||
`;
|
||||
|
||||
const SubContentWrapper = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
}
|
||||
.count {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
|
||||
.complete {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Hint = styled.div`
|
||||
background: var(--ads-v2-color-bg);
|
||||
padding: var(--ads-v2-spaces-4);
|
||||
margin-top: var(--ads-v2-spaces-5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid var(--ads-v2-color-border);
|
||||
border-radius: var(--ads-v2-border-radius);
|
||||
|
||||
.align-vertical {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.inner-wrapper {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.hint-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.hint-button {
|
||||
margin-top: ${(props) => props.theme.spaces[6]}px;
|
||||
}
|
||||
|
||||
.hint-steps {
|
||||
display: flex;
|
||||
margin-top: ${(props) => props.theme.spaces[5]}px;
|
||||
}
|
||||
|
||||
.strike {
|
||||
text-decoration: line-through;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.hint-steps-text {
|
||||
margin-left: ${(props) => props.theme.spaces[4]}px;
|
||||
}
|
||||
`;
|
||||
|
||||
const HintTextWrapper = styled.div`
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
height: 70px;
|
||||
width: 152px;
|
||||
}
|
||||
`;
|
||||
|
||||
const SuccessMessageWrapper = styled.div`
|
||||
display: flex;
|
||||
background: var(--ads-v2-color-bg);
|
||||
flex-direction: column;
|
||||
border: 1px solid var(--ads-v2-color-border);
|
||||
border-radius: var(--ads-v2-border-radius);
|
||||
|
||||
.wrapper {
|
||||
padding: var(--ads-v2-spaces-4);
|
||||
display: flex;
|
||||
}
|
||||
.info-wrapper {
|
||||
padding: var(--ads-v2-spaces-4);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.lottie-wrapper {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
.title-wrapper {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.success-message {
|
||||
color: var(--ads-v2-color-fg-emphasis);
|
||||
}
|
||||
`;
|
||||
|
||||
function InitialContent() {
|
||||
const dispatch = useDispatch();
|
||||
const isLoading = useSelector(loading);
|
||||
const queryAction = useSelector(getQueryAction);
|
||||
|
||||
const setupFirstStep = () => {
|
||||
dispatch(toggleLoader(true));
|
||||
dispatch(setUpTourApp());
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ContentWrapper>
|
||||
<SubContentWrapper>
|
||||
<Text className="guided-title" kind="heading-s" renderAs="h2">
|
||||
{createMessage(TITLE)}
|
||||
</Text>
|
||||
<Description>{createMessage(DESCRIPTION)}</Description>
|
||||
</SubContentWrapper>
|
||||
<GuideButton
|
||||
className="t--start-building"
|
||||
isLoading={isLoading}
|
||||
isVisible={!queryAction?.isLoading && !!queryAction?.data}
|
||||
onClick={setupFirstStep}
|
||||
size="md"
|
||||
>
|
||||
{createMessage(BUTTON_TEXT)}
|
||||
</GuideButton>
|
||||
</ContentWrapper>
|
||||
<Hint>
|
||||
<span className="hint-text">
|
||||
The app is connected to a Postgres database with customers data called{" "}
|
||||
<b>Customers DB</b>.
|
||||
</span>
|
||||
</Hint>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function GuideStepsContent(props: {
|
||||
currentStep: number;
|
||||
showInfoMessage: boolean;
|
||||
}) {
|
||||
const meta = useComputeCurrentStep(props.showInfoMessage);
|
||||
const content = Steps[props.currentStep];
|
||||
const [hintCount, setHintCount] = useState(0);
|
||||
const currentHint = content.hints[hintCount]
|
||||
? content.hints[hintCount]
|
||||
: content.hints[0];
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
setHintCount(0);
|
||||
}, [props.currentStep]);
|
||||
|
||||
useEffect(() => {
|
||||
setHintCount(meta.hintCount);
|
||||
}, [meta.hintCount]);
|
||||
|
||||
const hintSteps = currentHint.steps;
|
||||
|
||||
const hintButtonOnClick = () => {
|
||||
if (currentHint.button && currentHint.button.onClick) {
|
||||
currentHint.button.onClick(dispatch);
|
||||
}
|
||||
setHintCount((count) => count + 1);
|
||||
};
|
||||
|
||||
return (
|
||||
<div data-testid={"guided-tour-banner"}>
|
||||
<ContentWrapper>
|
||||
<SubContentWrapper>
|
||||
<div className="header">
|
||||
<TitleWrapper>
|
||||
<StepCount>{props.currentStep}</StepCount>
|
||||
<Text className="guided-title" kind="heading-s" renderAs="h2">
|
||||
{content.title}
|
||||
</Text>
|
||||
</TitleWrapper>
|
||||
<div className="count">
|
||||
{props.currentStep - 1}/{GUIDED_TOUR_STEPS.DEPLOY}
|
||||
{" "}
|
||||
<span className="complete">{createMessage(COMPLETE)}</span>
|
||||
</div>
|
||||
</div>
|
||||
{content.description && (
|
||||
<Description>{content.description}</Description>
|
||||
)}
|
||||
</SubContentWrapper>
|
||||
</ContentWrapper>
|
||||
<Hint>
|
||||
<div className="inner-wrapper hint-text">
|
||||
<HintTextWrapper>
|
||||
<div>{currentHint.text}</div>
|
||||
{currentHint.image && <img src={currentHint.image} />}
|
||||
{currentHint.button && (
|
||||
<GuideButton
|
||||
className="t--hint-button"
|
||||
onClick={hintButtonOnClick}
|
||||
size="md"
|
||||
>
|
||||
{createMessage(PROCEED)}
|
||||
</GuideButton>
|
||||
)}
|
||||
</HintTextWrapper>
|
||||
{isArray(hintSteps) &&
|
||||
hintSteps.length &&
|
||||
hintSteps.map((step, index) => {
|
||||
const completed = meta.completedSubSteps.includes(index);
|
||||
const className = "hint-steps" + (completed ? " strike" : "");
|
||||
|
||||
return (
|
||||
<div className={className} key={step?.toString()}>
|
||||
<Icon
|
||||
color={
|
||||
completed ? "var(--ads-v2-color-fg-success)" : "inherit"
|
||||
}
|
||||
name={completed ? "oval-check-fill" : "oval-check"}
|
||||
size="md"
|
||||
/>
|
||||
<span className="hint-steps-text">{hintSteps[index]}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Hint>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface CompletionContentProps {
|
||||
step: number;
|
||||
showInfoMessage: boolean;
|
||||
}
|
||||
|
||||
function CompletionContent(props: CompletionContentProps) {
|
||||
const [showSuccess, setShowSuccess] = useState(!props.showInfoMessage);
|
||||
const [showSuccessButton, setShowSuccessButton] = useState(false);
|
||||
const info = Steps[props.step].info;
|
||||
const success = Steps[props.step].success;
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const tickMarkRef = useRef<HTMLDivElement>(null);
|
||||
useEffect(() => {
|
||||
if (showSuccess) {
|
||||
const anim = lazyLottie.loadAnimation({
|
||||
path: tickMarkAnimationURL,
|
||||
autoplay: true,
|
||||
container: tickMarkRef?.current as HTMLDivElement,
|
||||
renderer: "svg",
|
||||
loop: false,
|
||||
});
|
||||
|
||||
return () => {
|
||||
anim.destroy();
|
||||
};
|
||||
}
|
||||
}, [tickMarkRef?.current, showSuccess]);
|
||||
|
||||
const onSuccessButtonClick = () => {
|
||||
setShowSuccess(false);
|
||||
success?.onClick && success?.onClick(dispatch);
|
||||
|
||||
if (info) {
|
||||
// We skip showing success message again
|
||||
dispatch(showInfoMessage());
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (success?.timed && showSuccess) {
|
||||
setTimeout(() => {
|
||||
setShowSuccessButton(true);
|
||||
}, 2000);
|
||||
}
|
||||
}, [success?.timed, showSuccess]);
|
||||
|
||||
const onInfoButtonClick = () => {
|
||||
info?.onClick(dispatch);
|
||||
};
|
||||
|
||||
if (showSuccess) {
|
||||
return (
|
||||
<SuccessMessageWrapper>
|
||||
<div className="wrapper">
|
||||
<div className="lottie-wrapper" ref={tickMarkRef} />
|
||||
<div className="title-wrapper">
|
||||
<Text className="success-message" kind="heading-s" renderAs="h2">
|
||||
{Steps[props.step].success?.text}
|
||||
</Text>
|
||||
{/* Show the button after a delay */}
|
||||
<GuideButton
|
||||
className="t--success-button"
|
||||
isVisible={showSuccessButton}
|
||||
onClick={onSuccessButtonClick}
|
||||
size="md"
|
||||
>
|
||||
{success?.buttonText ?? createMessage(CONTINUE)}
|
||||
</GuideButton>
|
||||
</div>
|
||||
</div>
|
||||
</SuccessMessageWrapper>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<SuccessMessageWrapper>
|
||||
<div className="wrapper info-wrapper">
|
||||
{info?.icon && (
|
||||
<Icon
|
||||
color="var(--ads-v2-color-fg-information)"
|
||||
name={info.icon}
|
||||
size="lg"
|
||||
/>
|
||||
)}
|
||||
<Description className="info">{info?.text}</Description>
|
||||
<GuideButton
|
||||
className="t--info-button"
|
||||
onClick={onInfoButtonClick}
|
||||
size="md"
|
||||
>
|
||||
{info?.buttonText ?? createMessage(PROCEED_TO_NEXT_STEP)}
|
||||
</GuideButton>
|
||||
</div>
|
||||
</SuccessMessageWrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export interface GuideBody {
|
||||
exploring: boolean;
|
||||
step: number;
|
||||
showInfoMessage: boolean;
|
||||
}
|
||||
|
||||
function GuideBody(props: GuideBody) {
|
||||
const successMessage = useSelector(showSuccessMessage);
|
||||
|
||||
if (props.exploring) {
|
||||
return <InitialContent />;
|
||||
} else if (successMessage || props.showInfoMessage) {
|
||||
return (
|
||||
<CompletionContent
|
||||
showInfoMessage={props.showInfoMessage}
|
||||
step={props.step}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<GuideStepsContent
|
||||
currentStep={props.step}
|
||||
showInfoMessage={props.showInfoMessage}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface GuideProps {
|
||||
className?: string;
|
||||
}
|
||||
// Guided tour steps
|
||||
function Guide(props: GuideProps) {
|
||||
const exploring = useSelector(isExploringSelector);
|
||||
const step = useSelector(getCurrentStep);
|
||||
const showInfoMessage = useSelector(showInfoMessageSelector);
|
||||
|
||||
return (
|
||||
<GuideWrapper className={props.className}>
|
||||
<CardWrapper>
|
||||
<UpperContent>
|
||||
<GuideBody
|
||||
exploring={exploring}
|
||||
showInfoMessage={showInfoMessage}
|
||||
step={step}
|
||||
/>
|
||||
</UpperContent>
|
||||
</CardWrapper>
|
||||
</GuideWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default Guide;
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import Rating from "react-rating";
|
||||
import { Button, Icon, Text } from "design-system";
|
||||
import {
|
||||
getPostWelcomeTourState,
|
||||
setPostWelcomeTourState,
|
||||
} from "utils/storage";
|
||||
import { getQueryParams } from "utils/URLUtils";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { showPostCompletionMessage } from "actions/onboardingActions";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import {
|
||||
createMessage,
|
||||
END_BUTTON_TEXT,
|
||||
END_DESCRIPTION,
|
||||
END_TITLE,
|
||||
RATING_DESCRIPTION,
|
||||
RATING_TEXT,
|
||||
RATING_TITLE,
|
||||
} from "@appsmith/constants/messages";
|
||||
import history from "utils/history";
|
||||
import { APPLICATIONS_URL } from "constants/routes";
|
||||
|
||||
const Container = styled.div`
|
||||
background-color: var(--ads-v2-color-bg-success);
|
||||
padding: var(--ads-v2-spaces-5);
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.title {
|
||||
color: var(--ads-v2-color-fg-emphasis);
|
||||
}
|
||||
`;
|
||||
|
||||
const Confetti = styled.span`
|
||||
font-size: 30px;
|
||||
margin-right: var(--ads-v2-spaces-5);
|
||||
`;
|
||||
|
||||
const Description = styled.div`
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
margin-top: var(--ads-v2-spaces-2);
|
||||
`;
|
||||
|
||||
const RatingText = styled.span`
|
||||
/* color: #000000; */
|
||||
`;
|
||||
|
||||
const RatingWrapper = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.star {
|
||||
padding: 0 5px;
|
||||
}
|
||||
`;
|
||||
|
||||
const Left = styled.div`
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
function CongratulationsView() {
|
||||
const [ratingComplete, setRatingComplete] = useState(false);
|
||||
const [show, setShow] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const onValueChanged = (value: number) => {
|
||||
AnalyticsUtil.logEvent("GUIDED_TOUR_RATING", {
|
||||
rating: value,
|
||||
});
|
||||
setRatingComplete(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const inPostCompletionState = async () => {
|
||||
const postCompletionMessage = await getPostWelcomeTourState();
|
||||
const queryParams = getQueryParams();
|
||||
|
||||
if (queryParams.guidedTourComplete === "true" && postCompletionMessage) {
|
||||
setShow(true);
|
||||
dispatch(showPostCompletionMessage(true));
|
||||
}
|
||||
};
|
||||
|
||||
inPostCompletionState();
|
||||
}, [dispatch]);
|
||||
|
||||
const hideMessage = () => {
|
||||
setShow(false);
|
||||
dispatch(showPostCompletionMessage(false));
|
||||
setPostWelcomeTourState(false);
|
||||
history.push(APPLICATIONS_URL);
|
||||
};
|
||||
|
||||
if (!show) return null;
|
||||
|
||||
if (!ratingComplete) {
|
||||
return (
|
||||
<Container>
|
||||
<Wrapper>
|
||||
<Left>
|
||||
<Confetti>🎉</Confetti>
|
||||
<div>
|
||||
<Text className="title" kind="heading-s" renderAs="h2">
|
||||
{createMessage(RATING_TITLE)}
|
||||
</Text>
|
||||
<Description>{createMessage(RATING_DESCRIPTION)}</Description>
|
||||
</div>
|
||||
</Left>
|
||||
<RatingWrapper>
|
||||
<RatingText>{createMessage(RATING_TEXT)}</RatingText>
|
||||
<Rating
|
||||
emptySymbol={
|
||||
<Icon
|
||||
className={"t--guided-tour-rating star"}
|
||||
color={"var(--ads-v2-color-fg-success)"}
|
||||
name="star-line"
|
||||
size="lg"
|
||||
/>
|
||||
}
|
||||
fullSymbol={
|
||||
<Icon
|
||||
className={"t--guided-tour-rating star"}
|
||||
color={"var(--ads-v2-color-fg-success)"}
|
||||
name="star-fill"
|
||||
size="lg"
|
||||
/>
|
||||
}
|
||||
onChange={onValueChanged}
|
||||
/>
|
||||
</RatingWrapper>
|
||||
</Wrapper>
|
||||
</Container>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Container>
|
||||
<Wrapper>
|
||||
<div>
|
||||
<Text className="title" kind="heading-s" renderAs="h2">
|
||||
{createMessage(END_TITLE)}
|
||||
</Text>
|
||||
<Description>{createMessage(END_DESCRIPTION)}</Description>
|
||||
</div>
|
||||
<Button className="t--start-building" onClick={hideMessage} size="md">
|
||||
{createMessage(END_BUTTON_TEXT)}
|
||||
</Button>
|
||||
</Wrapper>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CongratulationsView;
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,558 +0,0 @@
|
|||
import React from "react";
|
||||
import type { ReactNode } from "react";
|
||||
import type { Dispatch } from "redux";
|
||||
import TableData from "assets/gifs/table_data.gif";
|
||||
import DefaultText from "assets/gifs/default_text.gif";
|
||||
import {
|
||||
setCurrentStepInit,
|
||||
addOnboardingWidget,
|
||||
forceShowContent,
|
||||
focusWidget,
|
||||
} from "actions/onboardingActions";
|
||||
import { highlightSection, showIndicator } from "./utils";
|
||||
import { setExplorerPinnedAction } from "actions/explorerActions";
|
||||
import { forceOpenWidgetPanel } from "actions/widgetSidebarActions";
|
||||
import {
|
||||
createMessage,
|
||||
STEP_EIGHT_SUCCESS_TEXT,
|
||||
STEP_EIGHT_TITLE,
|
||||
STEP_FIVE_HINT_TEXT,
|
||||
STEP_FIVE_SUCCESS_BUTTON_TEXT,
|
||||
STEP_FIVE_SUCCESS_TEXT,
|
||||
STEP_FIVE_TITLE,
|
||||
STEP_FOUR_HINT_BUTTON_TEXT,
|
||||
STEP_FOUR_SUCCESS_BUTTON_TEXT,
|
||||
STEP_FOUR_SUCCESS_TEXT,
|
||||
STEP_FOUR_TITLE,
|
||||
STEP_NINE_TITLE,
|
||||
STEP_ONE_BUTTON_TEXT,
|
||||
STEP_ONE_SUCCESS_TEXT,
|
||||
STEP_ONE_TITLE,
|
||||
STEP_SEVEN_TITLE,
|
||||
STEP_SIX_SUCCESS_BUTTON_TEXT,
|
||||
STEP_SIX_SUCCESS_TEXT,
|
||||
STEP_SIX_TITLE,
|
||||
STEP_THREE_SUCCESS_BUTTON_TEXT,
|
||||
STEP_THREE_SUCCESS_TEXT,
|
||||
STEP_THREE_TITLE,
|
||||
STEP_TWO_TITLE,
|
||||
} from "@appsmith/constants/messages";
|
||||
import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants";
|
||||
import { getAssetUrl } from "@appsmith/utils/airgapHelpers";
|
||||
|
||||
export const Classes = {
|
||||
GUIDED_TOUR_BORDER: "guided-tour-border",
|
||||
GUIDED_TOUR_SHOW_BORDER: "guided-tour-show-border",
|
||||
GUIDED_TOUR_INDICATOR: "guided-tour-indicator",
|
||||
};
|
||||
|
||||
export const GuidedTourEntityNames = {
|
||||
BUTTON_WIDGET: "UpdateButton",
|
||||
NAME_INPUT: "NameInput",
|
||||
EMAIL_INPUT: "EmailInput",
|
||||
COUNTRY_INPUT: "CountryInput",
|
||||
DISPLAY_IMAGE: "DisplayImage",
|
||||
};
|
||||
|
||||
export enum GUIDED_TOUR_STEPS {
|
||||
DEFAULT = 0,
|
||||
RUN_QUERY = 1,
|
||||
SELECT_TABLE_WIDGET = 2,
|
||||
TABLE_WIDGET_BINDING = 3,
|
||||
NAME_INPUT_BINDING = 4,
|
||||
BIND_OTHER_FORM_WIDGETS = 5,
|
||||
ADD_BUTTON_WIDGET = 6,
|
||||
BUTTON_ONCLICK_BINDING = 7,
|
||||
BUTTON_ONSUCCESS_BINDING = 8,
|
||||
DEPLOY = 9,
|
||||
}
|
||||
|
||||
// We are using widget blueprints to create the form like container widget
|
||||
export const onboardingContainerBlueprint = {
|
||||
view: [
|
||||
{
|
||||
type: "CANVAS_WIDGET",
|
||||
position: { top: 0, left: 0 },
|
||||
props: {
|
||||
containerStyle: "none",
|
||||
canExtend: false,
|
||||
detachFromLayout: true,
|
||||
children: [],
|
||||
version: 1,
|
||||
blueprint: {
|
||||
view: [
|
||||
{
|
||||
type: "TEXT_WIDGET",
|
||||
position: {
|
||||
left: 1,
|
||||
top: 1,
|
||||
},
|
||||
size: {
|
||||
rows: 4,
|
||||
cols: 48,
|
||||
},
|
||||
props: {
|
||||
textAlign: "LEFT",
|
||||
fontStyle: "BOLD",
|
||||
version: 1,
|
||||
textColor: "#231F20",
|
||||
fontSize: "HEADING2",
|
||||
text: "\uD83D\uDC68\uD83D\uDCBC Customer Update Form",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "IMAGE_WIDGET",
|
||||
position: {
|
||||
left: 1,
|
||||
top: 6,
|
||||
},
|
||||
size: {
|
||||
rows: 12,
|
||||
cols: 16,
|
||||
},
|
||||
props: {
|
||||
imageShape: "RECTANGLE",
|
||||
defaultImage: getAssetUrl(
|
||||
`${ASSETS_CDN_URL}/widgets/default.png`,
|
||||
),
|
||||
objectFit: "contain",
|
||||
image: "{{CustomersTable.selectedRow.image}}",
|
||||
dynamicBindingPathList: [{ key: "image" }],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "TEXT_WIDGET",
|
||||
position: {
|
||||
top: 6,
|
||||
left: 19,
|
||||
},
|
||||
size: {
|
||||
rows: 4,
|
||||
cols: 8,
|
||||
},
|
||||
props: {
|
||||
text: "Name",
|
||||
textAlign: "LEFT",
|
||||
fontStyle: "BOLD",
|
||||
textColor: "#231F20",
|
||||
version: 1,
|
||||
fontSize: "PARAGRAPH",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "INPUT_WIDGET_V2",
|
||||
position: {
|
||||
top: 6,
|
||||
left: 30,
|
||||
},
|
||||
size: {
|
||||
rows: 4,
|
||||
cols: 32,
|
||||
},
|
||||
props: {
|
||||
inputType: "TEXT",
|
||||
label: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "TEXT_WIDGET",
|
||||
position: {
|
||||
top: 10,
|
||||
left: 19,
|
||||
},
|
||||
size: {
|
||||
rows: 4,
|
||||
cols: 8,
|
||||
},
|
||||
props: {
|
||||
text: "Email",
|
||||
textAlign: "LEFT",
|
||||
fontStyle: "BOLD",
|
||||
textColor: "#231F20",
|
||||
version: 1,
|
||||
fontSize: "PARAGRAPH",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "INPUT_WIDGET_V2",
|
||||
position: {
|
||||
top: 10,
|
||||
left: 30,
|
||||
},
|
||||
size: {
|
||||
rows: 4,
|
||||
cols: 32,
|
||||
},
|
||||
props: {
|
||||
inputType: "TEXT",
|
||||
label: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "TEXT_WIDGET",
|
||||
position: {
|
||||
top: 14,
|
||||
left: 19,
|
||||
},
|
||||
size: {
|
||||
rows: 4,
|
||||
cols: 10,
|
||||
},
|
||||
props: {
|
||||
text: "Country",
|
||||
textAlign: "LEFT",
|
||||
fontStyle: "BOLD",
|
||||
textColor: "#231F20",
|
||||
version: 1,
|
||||
fontSize: "PARAGRAPH",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "INPUT_WIDGET_V2",
|
||||
position: {
|
||||
top: 14,
|
||||
left: 30,
|
||||
},
|
||||
size: {
|
||||
rows: 4,
|
||||
cols: 32,
|
||||
},
|
||||
props: {
|
||||
inputType: "TEXT",
|
||||
label: "",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
interface Step {
|
||||
title: string;
|
||||
description?: string;
|
||||
elementSelector?: string;
|
||||
hints: {
|
||||
text: ReactNode;
|
||||
image?: string;
|
||||
button?: {
|
||||
text: string;
|
||||
onClick?: (dispatch: Dispatch<any>) => void;
|
||||
};
|
||||
steps?: ReactNode[];
|
||||
}[];
|
||||
success?: {
|
||||
text: string;
|
||||
onClick?: (dispatch: Dispatch<any>) => void;
|
||||
timed?: boolean;
|
||||
buttonText?: string;
|
||||
};
|
||||
info?: {
|
||||
icon: string;
|
||||
text: ReactNode;
|
||||
onClick: (dispatch: Dispatch<any>) => void;
|
||||
buttonText?: string;
|
||||
};
|
||||
}
|
||||
type StepsType = Record<number, Step>;
|
||||
|
||||
export const Steps: StepsType = {
|
||||
[GUIDED_TOUR_STEPS.RUN_QUERY]: {
|
||||
title: createMessage(STEP_ONE_TITLE),
|
||||
elementSelector: "query-table-response",
|
||||
hints: [
|
||||
{
|
||||
text: (
|
||||
<>
|
||||
This command will fetch the first 20 items in the user_data
|
||||
database. Hit <b>Run</b> to see the response.
|
||||
</>
|
||||
),
|
||||
},
|
||||
],
|
||||
success: {
|
||||
text: createMessage(STEP_ONE_SUCCESS_TEXT),
|
||||
onClick: (dispatch) => {
|
||||
dispatch(setExplorerPinnedAction(true));
|
||||
dispatch(setCurrentStepInit(GUIDED_TOUR_STEPS.SELECT_TABLE_WIDGET));
|
||||
setTimeout(() => {
|
||||
showIndicator(`[data-guided-tour-iid='CustomersTable']`, "right", {
|
||||
top: 5,
|
||||
left: -15,
|
||||
});
|
||||
}, 1000);
|
||||
},
|
||||
buttonText: createMessage(STEP_ONE_BUTTON_TEXT),
|
||||
timed: true,
|
||||
},
|
||||
},
|
||||
[GUIDED_TOUR_STEPS.SELECT_TABLE_WIDGET]: {
|
||||
title: createMessage(STEP_TWO_TITLE),
|
||||
hints: [
|
||||
{
|
||||
text: (
|
||||
<>
|
||||
<b>Click on the CustomersTable widget</b> in the explorer on the
|
||||
left.
|
||||
</>
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
[GUIDED_TOUR_STEPS.TABLE_WIDGET_BINDING]: {
|
||||
title: createMessage(STEP_THREE_TITLE),
|
||||
hints: [
|
||||
{
|
||||
text: (
|
||||
<>
|
||||
Bind the response by typing{" "}
|
||||
<b>
|
||||
<code>
|
||||
{{
|
||||
{"getCustomers.data"}}}
|
||||
</code>
|
||||
</b>{" "}
|
||||
in the Table data input field on the right pane.
|
||||
</>
|
||||
),
|
||||
image: TableData,
|
||||
},
|
||||
],
|
||||
success: {
|
||||
text: createMessage(STEP_THREE_SUCCESS_TEXT),
|
||||
onClick: (dispatch) => {
|
||||
// Stop hiding rest of the properties in the propery pane
|
||||
dispatch(forceShowContent(GUIDED_TOUR_STEPS.TABLE_WIDGET_BINDING));
|
||||
setTimeout(() => {
|
||||
highlightSection("property-pane");
|
||||
}, 1000);
|
||||
},
|
||||
timed: true,
|
||||
buttonText: createMessage(STEP_THREE_SUCCESS_BUTTON_TEXT),
|
||||
},
|
||||
info: {
|
||||
icon: "lightbulb-flash-line",
|
||||
text: (
|
||||
<>
|
||||
The pane on the right is called the <b>Property Pane</b>. Here
|
||||
you can modify properties, data, or styling for every widget.
|
||||
</>
|
||||
),
|
||||
onClick: (dispatch) => {
|
||||
dispatch(setCurrentStepInit(GUIDED_TOUR_STEPS.NAME_INPUT_BINDING));
|
||||
dispatch(
|
||||
addOnboardingWidget({
|
||||
type: "CONTAINER_WIDGET",
|
||||
widgetName: "CustomersInfo",
|
||||
topRow: 7,
|
||||
rows: 30,
|
||||
columns: 29,
|
||||
leftColumn: 35,
|
||||
props: {
|
||||
blueprint: onboardingContainerBlueprint,
|
||||
},
|
||||
}),
|
||||
);
|
||||
},
|
||||
buttonText: "Got it",
|
||||
},
|
||||
},
|
||||
[GUIDED_TOUR_STEPS.NAME_INPUT_BINDING]: {
|
||||
title: createMessage(STEP_FOUR_TITLE),
|
||||
hints: [
|
||||
{
|
||||
text: (
|
||||
<>
|
||||
We{"'"}ll{" "}
|
||||
<b>
|
||||
display the data from a table{"'"}s selected row inside an input
|
||||
field.
|
||||
</b>
|
||||
<br /> This will let us see the data before we update it.
|
||||
</>
|
||||
),
|
||||
button: {
|
||||
text: createMessage(STEP_FOUR_HINT_BUTTON_TEXT),
|
||||
onClick: (dispatch) => {
|
||||
// Select the NameInput widget and focus the defaultText input field
|
||||
dispatch(focusWidget("NameInput", "defaultText"));
|
||||
setTimeout(() => {
|
||||
showIndicator(`[data-guided-tour-iid='defaultText']`, "top", {
|
||||
top: 20,
|
||||
left: 0,
|
||||
});
|
||||
}, 1000);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text: (
|
||||
<>
|
||||
In the property pane of {GuidedTourEntityNames.NAME_INPUT}, add the{" "}
|
||||
<b>
|
||||
<code>
|
||||
{{CustomersTable.selectedRow.name}}
|
||||
</code>
|
||||
</b>{" "}
|
||||
binding to the <b>Default Text</b> property
|
||||
</>
|
||||
),
|
||||
// Get gif from url
|
||||
image: DefaultText,
|
||||
},
|
||||
],
|
||||
success: {
|
||||
text: createMessage(STEP_FOUR_SUCCESS_TEXT),
|
||||
timed: true,
|
||||
onClick: (dispatch) => {
|
||||
dispatch(setCurrentStepInit(GUIDED_TOUR_STEPS.BIND_OTHER_FORM_WIDGETS));
|
||||
dispatch(focusWidget("EmailInput", "defaultText"));
|
||||
setTimeout(() => {
|
||||
showIndicator(`[data-guided-tour-iid='defaultText']`, "top", {
|
||||
top: 20,
|
||||
left: 0,
|
||||
});
|
||||
}, 1000);
|
||||
},
|
||||
buttonText: createMessage(STEP_FOUR_SUCCESS_BUTTON_TEXT),
|
||||
},
|
||||
},
|
||||
[GUIDED_TOUR_STEPS.BIND_OTHER_FORM_WIDGETS]: {
|
||||
title: createMessage(STEP_FIVE_TITLE),
|
||||
hints: [
|
||||
{
|
||||
text: <>{createMessage(STEP_FIVE_HINT_TEXT)}</>,
|
||||
steps: [
|
||||
<>
|
||||
Connect <b>{GuidedTourEntityNames.EMAIL_INPUT}</b>
|
||||
{"'"}s Default Text Property to{" "}
|
||||
<code>
|
||||
{{CustomersTable.selectedRow.email}}
|
||||
</code>
|
||||
</>,
|
||||
<>
|
||||
Connect <b>{GuidedTourEntityNames.COUNTRY_INPUT}</b>
|
||||
{"'"}s Default Text Property to{" "}
|
||||
<code>
|
||||
{{CustomersTable.selectedRow.country}}
|
||||
</code>
|
||||
</>,
|
||||
],
|
||||
},
|
||||
],
|
||||
success: {
|
||||
text: createMessage(STEP_FIVE_SUCCESS_TEXT),
|
||||
onClick: (dispatch) => {
|
||||
dispatch(setCurrentStepInit(GUIDED_TOUR_STEPS.ADD_BUTTON_WIDGET));
|
||||
dispatch(setExplorerPinnedAction(true));
|
||||
dispatch(forceOpenWidgetPanel(true));
|
||||
setTimeout(() => {
|
||||
highlightSection("widget-card-buttonwidget");
|
||||
}, 2000);
|
||||
},
|
||||
timed: true,
|
||||
buttonText: createMessage(STEP_FIVE_SUCCESS_BUTTON_TEXT),
|
||||
},
|
||||
},
|
||||
[GUIDED_TOUR_STEPS.ADD_BUTTON_WIDGET]: {
|
||||
title: createMessage(STEP_SIX_TITLE),
|
||||
hints: [
|
||||
{
|
||||
text: (
|
||||
<>
|
||||
Switch to the widget pane and then <b>Drag {"&"} Drop</b> a{" "}
|
||||
<b>Button</b> widget into the left bottom of container, below the
|
||||
image.
|
||||
</>
|
||||
),
|
||||
},
|
||||
],
|
||||
success: {
|
||||
text: createMessage(STEP_SIX_SUCCESS_TEXT),
|
||||
timed: true,
|
||||
onClick: (dispatch) => {
|
||||
dispatch(forceOpenWidgetPanel(false));
|
||||
setTimeout(() => {
|
||||
highlightSection("explorer-entity-updateCustomerInfo");
|
||||
}, 1000);
|
||||
},
|
||||
buttonText: createMessage(STEP_SIX_SUCCESS_BUTTON_TEXT),
|
||||
},
|
||||
info: {
|
||||
icon: "lightbulb-flash-line",
|
||||
text: (
|
||||
<>
|
||||
To <b>update the customers</b> through the button, we
|
||||
created an <b>updateCustomerInfo query</b> for you which is
|
||||
ready to use
|
||||
</>
|
||||
),
|
||||
onClick: (dispatch) => {
|
||||
dispatch(focusWidget(GuidedTourEntityNames.BUTTON_WIDGET));
|
||||
dispatch(setCurrentStepInit(GUIDED_TOUR_STEPS.BUTTON_ONCLICK_BINDING));
|
||||
requestAnimationFrame(() => {
|
||||
showIndicator(`[data-guided-tour-iid='onClick']`, "top", {
|
||||
top: 25,
|
||||
left: 0,
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
[GUIDED_TOUR_STEPS.BUTTON_ONCLICK_BINDING]: {
|
||||
title: createMessage(STEP_SEVEN_TITLE),
|
||||
hints: [
|
||||
{
|
||||
text: (
|
||||
<>
|
||||
Select the button widget to see the properties in the property pane.
|
||||
Click the <b>+</b> button beside the onClick property to add an
|
||||
action, select <b>Execute a query</b> {"&"} then select{" "}
|
||||
<b>updateCustomerInfo</b> query
|
||||
</>
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
[GUIDED_TOUR_STEPS.BUTTON_ONSUCCESS_BINDING]: {
|
||||
title: createMessage(STEP_EIGHT_TITLE),
|
||||
hints: [
|
||||
{
|
||||
text: (
|
||||
<>
|
||||
Expand <b>Callbacks</b> section, click the <b>+</b> button beside{" "}
|
||||
<b>On success</b>, select <b>Execute a query</b> {"&"} then choose{" "}
|
||||
<b>getCustomers</b> Query
|
||||
</>
|
||||
),
|
||||
},
|
||||
],
|
||||
success: {
|
||||
text: createMessage(STEP_EIGHT_SUCCESS_TEXT),
|
||||
onClick: (dispatch) => {
|
||||
dispatch(setCurrentStepInit(GUIDED_TOUR_STEPS.DEPLOY));
|
||||
setTimeout(() => {
|
||||
showIndicator(`[data-guided-tour-iid='deploy']`, "bottom", {
|
||||
top: -6,
|
||||
left: 0,
|
||||
});
|
||||
}, 1000);
|
||||
},
|
||||
timed: true,
|
||||
},
|
||||
},
|
||||
[GUIDED_TOUR_STEPS.DEPLOY]: {
|
||||
title: createMessage(STEP_NINE_TITLE),
|
||||
hints: [
|
||||
{
|
||||
text: (
|
||||
<>
|
||||
Test your app and ensure there are no errors. When you are ready,
|
||||
click <b>Deploy</b> to deploy this app to a URL.
|
||||
</>
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -1,338 +0,0 @@
|
|||
import {
|
||||
markStepComplete,
|
||||
tableWidgetWasSelected,
|
||||
enableGuidedTour,
|
||||
updateButtonWidgetText,
|
||||
forceShowContent,
|
||||
focusWidgetProperty,
|
||||
setCurrentStepInit,
|
||||
disableStartSignpostingAction,
|
||||
} from "actions/onboardingActions";
|
||||
import { useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { getApplicationLastDeployedAt } from "selectors/editorSelectors";
|
||||
import {
|
||||
getHadReachedStep,
|
||||
isQueryExecutionSuccessful,
|
||||
isTableWidgetSelected,
|
||||
tableWidgetHasBinding,
|
||||
containerWidgetAdded,
|
||||
nameInputSelector,
|
||||
isNameInputBoundSelector,
|
||||
isCountryInputBound,
|
||||
isEmailInputBound,
|
||||
isButtonWidgetPresent,
|
||||
buttonWidgetHasOnClickBinding,
|
||||
buttonWidgetHasOnSuccessBinding,
|
||||
countryInputSelector,
|
||||
} from "selectors/onboardingSelectors";
|
||||
import { getBaseWidgetClassName } from "constants/componentClassNameConstants";
|
||||
import { GUIDED_TOUR_STEPS, Steps } from "./constants";
|
||||
import {
|
||||
closeSidebar,
|
||||
hideIndicator,
|
||||
highlightSection,
|
||||
showIndicator,
|
||||
} from "./utils";
|
||||
|
||||
function useComputeCurrentStep(showInfoMessage: boolean) {
|
||||
let step = 1;
|
||||
const meta: {
|
||||
completedSubSteps: number[];
|
||||
hintCount: number;
|
||||
} = {
|
||||
completedSubSteps: [],
|
||||
hintCount: 0,
|
||||
};
|
||||
const dispatch = useDispatch();
|
||||
const hadReachedStep = useSelector(getHadReachedStep);
|
||||
// Step 1(Run the query) selectors
|
||||
const queryExecutedSuccessfully = useSelector(isQueryExecutionSuccessful);
|
||||
// 2 selectors
|
||||
const tableWidgetSelected = useSelector(isTableWidgetSelected);
|
||||
// 3
|
||||
const isTableWidgetBound = useSelector(tableWidgetHasBinding);
|
||||
// 4
|
||||
const isContainerWidgetPreset = useSelector(containerWidgetAdded);
|
||||
const nameInputWidgetId = useSelector(nameInputSelector);
|
||||
const isNameInputBound = useSelector(isNameInputBoundSelector);
|
||||
// 5
|
||||
const countryInputBound = useSelector(isCountryInputBound);
|
||||
const isCountryInputSelected = useSelector(countryInputSelector);
|
||||
const emailInputBound = useSelector(isEmailInputBound);
|
||||
// 6
|
||||
const buttonWidgetPresent = useSelector(isButtonWidgetPresent);
|
||||
// 7
|
||||
const buttonWidgetonClickBinding = useSelector(buttonWidgetHasOnClickBinding);
|
||||
// 8
|
||||
const buttonWidgetSuccessBinding = useSelector(
|
||||
buttonWidgetHasOnSuccessBinding,
|
||||
);
|
||||
// 9
|
||||
const isDeployed = useSelector(getApplicationLastDeployedAt);
|
||||
|
||||
// If we are on the first step
|
||||
if (step === GUIDED_TOUR_STEPS.RUN_QUERY) {
|
||||
// If the query is executed successfully and if the user had gone to further steps before
|
||||
// i.e probably the user is here after finishing step 5. This can happen if the query is updated
|
||||
// to something unexpected.
|
||||
// So we have `hadReachedStep` to keep track of the furthest the user had reached.
|
||||
// Initially we don't automatically go to the next step, instead the user clicks on a button in the guide
|
||||
// shown on top of the screen for the user clicking on which we update the current step
|
||||
if (queryExecutedSuccessfully && hadReachedStep > 1) {
|
||||
step = GUIDED_TOUR_STEPS.SELECT_TABLE_WIDGET;
|
||||
}
|
||||
}
|
||||
|
||||
// On the second step
|
||||
if (step === GUIDED_TOUR_STEPS.SELECT_TABLE_WIDGET) {
|
||||
if (tableWidgetSelected) {
|
||||
step = GUIDED_TOUR_STEPS.TABLE_WIDGET_BINDING;
|
||||
// Reset back the hintcount set in previous step
|
||||
meta.hintCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (step === GUIDED_TOUR_STEPS.TABLE_WIDGET_BINDING) {
|
||||
if (
|
||||
!!isTableWidgetBound &&
|
||||
isContainerWidgetPreset &&
|
||||
hadReachedStep > GUIDED_TOUR_STEPS.TABLE_WIDGET_BINDING
|
||||
) {
|
||||
step = GUIDED_TOUR_STEPS.NAME_INPUT_BINDING;
|
||||
}
|
||||
}
|
||||
|
||||
if (step === GUIDED_TOUR_STEPS.NAME_INPUT_BINDING) {
|
||||
if (!!isNameInputBound && hadReachedStep > 4) {
|
||||
step = GUIDED_TOUR_STEPS.BIND_OTHER_FORM_WIDGETS;
|
||||
}
|
||||
}
|
||||
|
||||
if (step === GUIDED_TOUR_STEPS.BIND_OTHER_FORM_WIDGETS) {
|
||||
if (emailInputBound) {
|
||||
// We tick off widgets in the UI which are bound to the selected row.
|
||||
// This is to keep track of which ones are bound
|
||||
meta.completedSubSteps.push(0);
|
||||
}
|
||||
if (countryInputBound) {
|
||||
meta.completedSubSteps.push(1);
|
||||
}
|
||||
// Once all three widgets are bound this step is complete
|
||||
if (
|
||||
meta.completedSubSteps.length === 2 &&
|
||||
hadReachedStep > GUIDED_TOUR_STEPS.BIND_OTHER_FORM_WIDGETS
|
||||
) {
|
||||
step = GUIDED_TOUR_STEPS.ADD_BUTTON_WIDGET;
|
||||
}
|
||||
}
|
||||
|
||||
if (step === GUIDED_TOUR_STEPS.ADD_BUTTON_WIDGET) {
|
||||
if (buttonWidgetPresent && hadReachedStep > 6) {
|
||||
step = GUIDED_TOUR_STEPS.BUTTON_ONCLICK_BINDING;
|
||||
}
|
||||
}
|
||||
|
||||
if (step === GUIDED_TOUR_STEPS.BUTTON_ONCLICK_BINDING) {
|
||||
if (buttonWidgetonClickBinding) {
|
||||
step = GUIDED_TOUR_STEPS.BUTTON_ONSUCCESS_BINDING;
|
||||
}
|
||||
}
|
||||
|
||||
if (step === GUIDED_TOUR_STEPS.BUTTON_ONSUCCESS_BINDING) {
|
||||
if (
|
||||
buttonWidgetSuccessBinding &&
|
||||
hadReachedStep > GUIDED_TOUR_STEPS.BUTTON_ONSUCCESS_BINDING
|
||||
) {
|
||||
step = GUIDED_TOUR_STEPS.DEPLOY;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the step in the store
|
||||
useEffect(() => {
|
||||
dispatch(setCurrentStepInit(step));
|
||||
}, [step]);
|
||||
|
||||
// Step 1 side effects
|
||||
useEffect(() => {
|
||||
// Success messages, indicators and highlighted sections are shown initially
|
||||
// These are not shown again i.e if the user finishes step 5 and does some changes
|
||||
// which bring the step back to 1, we don't do the following changes after completing step 1
|
||||
// again.
|
||||
if (
|
||||
step === GUIDED_TOUR_STEPS.RUN_QUERY &&
|
||||
hadReachedStep <= GUIDED_TOUR_STEPS.RUN_QUERY
|
||||
) {
|
||||
if (queryExecutedSuccessfully) {
|
||||
dispatch(forceShowContent(GUIDED_TOUR_STEPS.RUN_QUERY));
|
||||
// Hide the indicator after the user has successfully run the query
|
||||
hideIndicator();
|
||||
// This show the success message
|
||||
dispatch(markStepComplete());
|
||||
|
||||
setTimeout(() => {
|
||||
if (Steps[GUIDED_TOUR_STEPS.RUN_QUERY].elementSelector) {
|
||||
// Highlight section which shows a temporary border around the target
|
||||
highlightSection(
|
||||
Steps[GUIDED_TOUR_STEPS.RUN_QUERY].elementSelector,
|
||||
);
|
||||
}
|
||||
// Adding a slight delay to wait for the table to be visible
|
||||
}, 1000);
|
||||
} else {
|
||||
dispatch(closeSidebar());
|
||||
showIndicator(`[data-guided-tour-iid='run-query']`, "top");
|
||||
}
|
||||
}
|
||||
}, [queryExecutedSuccessfully, step, hadReachedStep]);
|
||||
|
||||
// Step 3(table widget binding) side effects
|
||||
// Focus the tableData input in the property pane
|
||||
useEffect(() => {
|
||||
if (
|
||||
tableWidgetSelected &&
|
||||
step === GUIDED_TOUR_STEPS.TABLE_WIDGET_BINDING &&
|
||||
hadReachedStep <= GUIDED_TOUR_STEPS.TABLE_WIDGET_BINDING
|
||||
) {
|
||||
dispatch(tableWidgetWasSelected(true));
|
||||
showIndicator(`[data-guided-tour-iid='tableData']`, "top", {
|
||||
top: 20,
|
||||
left: 0,
|
||||
});
|
||||
// Focus the tableData input field
|
||||
dispatch(focusWidgetProperty("tableData"));
|
||||
}
|
||||
}, [step, tableWidgetSelected]);
|
||||
// Show success message
|
||||
useEffect(() => {
|
||||
if (
|
||||
!!isTableWidgetBound &&
|
||||
step === GUIDED_TOUR_STEPS.TABLE_WIDGET_BINDING &&
|
||||
hadReachedStep <= GUIDED_TOUR_STEPS.TABLE_WIDGET_BINDING
|
||||
) {
|
||||
dispatch(closeSidebar());
|
||||
hideIndicator();
|
||||
dispatch(markStepComplete());
|
||||
}
|
||||
}, [isTableWidgetBound, step, hadReachedStep]);
|
||||
|
||||
// Step 4(Add binding to the NameInput widget) side effects
|
||||
// Highlight table widget's selected row
|
||||
useEffect(() => {
|
||||
if (
|
||||
!!isTableWidgetBound &&
|
||||
step === GUIDED_TOUR_STEPS.NAME_INPUT_BINDING &&
|
||||
hadReachedStep <= GUIDED_TOUR_STEPS.NAME_INPUT_BINDING
|
||||
) {
|
||||
if (!!nameInputWidgetId) {
|
||||
// Minor timeout to wait for the elements to exist
|
||||
dispatch(closeSidebar());
|
||||
setTimeout(() => {
|
||||
// Highlight the selected row and the NameInput widget
|
||||
highlightSection(
|
||||
"selected-row",
|
||||
getBaseWidgetClassName(isTableWidgetBound),
|
||||
"class",
|
||||
);
|
||||
highlightSection(
|
||||
getBaseWidgetClassName(nameInputWidgetId),
|
||||
undefined,
|
||||
"class",
|
||||
);
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
}, [isTableWidgetBound, step, hadReachedStep, nameInputWidgetId]);
|
||||
// Show success message
|
||||
useEffect(() => {
|
||||
if (
|
||||
step === GUIDED_TOUR_STEPS.NAME_INPUT_BINDING &&
|
||||
hadReachedStep <= GUIDED_TOUR_STEPS.NAME_INPUT_BINDING
|
||||
) {
|
||||
if (!!isNameInputBound) {
|
||||
hideIndicator();
|
||||
dispatch(markStepComplete());
|
||||
}
|
||||
}
|
||||
}, [isNameInputBound, step, hadReachedStep]);
|
||||
|
||||
// Step 5
|
||||
useEffect(() => {
|
||||
if (
|
||||
step === GUIDED_TOUR_STEPS.BIND_OTHER_FORM_WIDGETS &&
|
||||
hadReachedStep <= GUIDED_TOUR_STEPS.BIND_OTHER_FORM_WIDGETS
|
||||
) {
|
||||
if (isCountryInputSelected) {
|
||||
if (!countryInputBound) {
|
||||
showIndicator(`[data-guided-tour-iid='defaultText']`, "top", {
|
||||
top: 20,
|
||||
left: 0,
|
||||
});
|
||||
} else {
|
||||
hideIndicator();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [step, hadReachedStep, countryInputBound, isCountryInputSelected]);
|
||||
|
||||
// Show success message
|
||||
useEffect(() => {
|
||||
if (
|
||||
step === GUIDED_TOUR_STEPS.BIND_OTHER_FORM_WIDGETS &&
|
||||
hadReachedStep <= GUIDED_TOUR_STEPS.BIND_OTHER_FORM_WIDGETS
|
||||
) {
|
||||
if (meta.completedSubSteps.length === 1) {
|
||||
hideIndicator();
|
||||
}
|
||||
if (meta.completedSubSteps.length === 2) {
|
||||
dispatch(markStepComplete());
|
||||
}
|
||||
}
|
||||
}, [step, meta.completedSubSteps.length, hadReachedStep]);
|
||||
|
||||
// 6
|
||||
useEffect(() => {
|
||||
if (
|
||||
step === GUIDED_TOUR_STEPS.ADD_BUTTON_WIDGET &&
|
||||
hadReachedStep <= GUIDED_TOUR_STEPS.ADD_BUTTON_WIDGET &&
|
||||
!showInfoMessage
|
||||
) {
|
||||
if (buttonWidgetPresent) {
|
||||
dispatch(updateButtonWidgetText());
|
||||
dispatch(markStepComplete());
|
||||
}
|
||||
}
|
||||
}, [step, buttonWidgetPresent, showInfoMessage]);
|
||||
|
||||
// 8
|
||||
useEffect(() => {
|
||||
if (
|
||||
step === GUIDED_TOUR_STEPS.BUTTON_ONSUCCESS_BINDING &&
|
||||
hadReachedStep <= GUIDED_TOUR_STEPS.BUTTON_ONSUCCESS_BINDING
|
||||
) {
|
||||
if (buttonWidgetSuccessBinding) {
|
||||
dispatch(markStepComplete());
|
||||
hideIndicator();
|
||||
} else {
|
||||
showIndicator(`[data-guided-tour-iid='onSuccess']`, "top", {
|
||||
top: 20,
|
||||
left: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [step, hadReachedStep, buttonWidgetSuccessBinding]);
|
||||
|
||||
useEffect(() => {
|
||||
if (step === GUIDED_TOUR_STEPS.DEPLOY) {
|
||||
if (isDeployed) {
|
||||
hideIndicator();
|
||||
dispatch(enableGuidedTour(false));
|
||||
dispatch(disableStartSignpostingAction());
|
||||
}
|
||||
}
|
||||
}, [step, isDeployed]);
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
export default useComputeCurrentStep;
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import React from "react";
|
||||
import WidgetsEditorEntityExplorer from "../../WidgetsEditorEntityExplorer";
|
||||
import { useSelector } from "react-redux";
|
||||
import styled from "styled-components";
|
||||
import { Switch, useRouteMatch } from "react-router";
|
||||
import { SentryRoute } from "@appsmith/AppRouter";
|
||||
|
|
@ -15,7 +14,6 @@ import {
|
|||
import AppSettingsPane from "./AppSettings";
|
||||
import DataSidePane from "./DataSidePane";
|
||||
import LibrarySidePane from "./LibrarySidePane";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import { useIsAppSidebarEnabled } from "../../../../navigation/featureFlagHooks";
|
||||
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
|
||||
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
|
||||
|
|
@ -33,8 +31,7 @@ const LeftPane = () => {
|
|||
FEATURE_FLAG.release_show_new_sidebar_pages_pane_enabled,
|
||||
);
|
||||
const { path } = useRouteMatch();
|
||||
const guidedTourEnabled = useSelector(inGuidedTour);
|
||||
if (!isAppSidebarEnabled || guidedTourEnabled) {
|
||||
if (!isAppSidebarEnabled) {
|
||||
return <WidgetsEditorEntityExplorer />;
|
||||
}
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import history, { NavigationMethod } from "utils/history";
|
|||
import { useCurrentAppState } from "../hooks";
|
||||
import { getCurrentWorkspaceId } from "@appsmith/selectors/workspaceSelectors";
|
||||
import { fetchWorkspace } from "@appsmith/actions/workspaceActions";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import SidebarComponent from "./SidebarComponent";
|
||||
import { BottomButtons, TopButtons } from "@appsmith/entities/IDE/constants";
|
||||
|
||||
|
|
@ -20,7 +19,6 @@ function Sidebar() {
|
|||
const pageId = useSelector(getCurrentPageId);
|
||||
|
||||
const currentWorkspaceId = useSelector(getCurrentWorkspaceId);
|
||||
const guidedTourEnabled = useSelector(inGuidedTour);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchWorkspace(currentWorkspaceId));
|
||||
|
|
@ -41,10 +39,6 @@ function Sidebar() {
|
|||
[pageId],
|
||||
);
|
||||
|
||||
if (guidedTourEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarComponent
|
||||
appState={appState}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ import React from "react";
|
|||
import PropertyControl from "./PropertyControl";
|
||||
import PropertySection from "./PropertySection";
|
||||
import type { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig";
|
||||
import Boxed from "../GuidedTour/Boxed";
|
||||
import { GUIDED_TOUR_STEPS } from "../GuidedTour/constants";
|
||||
import { EmptySearchResult } from "./EmptySearchResult";
|
||||
import { useSelector } from "react-redux";
|
||||
import { getWidgetPropsForPropertyPane } from "selectors/propertyPaneSelectors";
|
||||
|
|
@ -43,55 +41,38 @@ const generatePropertyControl = (
|
|||
const sectionConfig: PropertyPaneSectionConfig =
|
||||
config as PropertyPaneSectionConfig;
|
||||
return (
|
||||
<Boxed
|
||||
<PropertySection
|
||||
childrenId={sectionConfig.childrenId}
|
||||
collapsible={sectionConfig.collapsible ?? true}
|
||||
hidden={sectionConfig.hidden}
|
||||
id={config.id || sectionConfig.sectionName}
|
||||
isDefaultOpen={sectionConfig.isDefaultOpen}
|
||||
key={config.id + props.id}
|
||||
show={
|
||||
sectionConfig.sectionName !== "General" &&
|
||||
props.type === "TABLE_WIDGET"
|
||||
}
|
||||
step={GUIDED_TOUR_STEPS.TABLE_WIDGET_BINDING}
|
||||
name={sectionConfig.sectionName}
|
||||
panelPropertyPath={props.panelPropertyPath}
|
||||
propertyPath={sectionConfig.propertySectionPath}
|
||||
tag={sectionConfig.tag}
|
||||
>
|
||||
<PropertySection
|
||||
childrenId={sectionConfig.childrenId}
|
||||
collapsible={sectionConfig.collapsible ?? true}
|
||||
hidden={sectionConfig.hidden}
|
||||
id={config.id || sectionConfig.sectionName}
|
||||
isDefaultOpen={sectionConfig.isDefaultOpen}
|
||||
name={sectionConfig.sectionName}
|
||||
panelPropertyPath={props.panelPropertyPath}
|
||||
propertyPath={sectionConfig.propertySectionPath}
|
||||
tag={sectionConfig.tag}
|
||||
>
|
||||
{config.children &&
|
||||
generatePropertyControl(
|
||||
config.children,
|
||||
props,
|
||||
isSearchResult,
|
||||
enhancements,
|
||||
)}
|
||||
</PropertySection>
|
||||
</Boxed>
|
||||
{config.children &&
|
||||
generatePropertyControl(
|
||||
config.children,
|
||||
props,
|
||||
isSearchResult,
|
||||
enhancements,
|
||||
)}
|
||||
</PropertySection>
|
||||
);
|
||||
} else if ((config as PropertyPaneControlConfig).controlType) {
|
||||
return (
|
||||
<Boxed
|
||||
<PropertyControl
|
||||
isPanelProperty={!!props.isPanelProperty}
|
||||
key={config.id + props.id}
|
||||
show={
|
||||
(config as PropertyPaneControlConfig).propertyName !==
|
||||
"tableData" && props.type === "TABLE_WIDGET"
|
||||
}
|
||||
step={GUIDED_TOUR_STEPS.TABLE_WIDGET_BINDING}
|
||||
>
|
||||
<PropertyControl
|
||||
isPanelProperty={!!props.isPanelProperty}
|
||||
key={config.id + props.id}
|
||||
{...(config as PropertyPaneControlConfig)}
|
||||
enhancements={enhancements}
|
||||
isSearchResult={isSearchResult}
|
||||
panel={props.panel}
|
||||
theme={props.theme}
|
||||
/>
|
||||
</Boxed>
|
||||
{...(config as PropertyPaneControlConfig)}
|
||||
enhancements={enhancements}
|
||||
isSearchResult={isSearchResult}
|
||||
panel={props.panel}
|
||||
theme={props.theme}
|
||||
/>
|
||||
);
|
||||
}
|
||||
throw Error("Unknown configuration provided: " + props.type);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import { ENTITY_TYPE } from "entities/AppsmithConsole";
|
|||
import { DebugButton } from "components/editorComponents/Debugger/DebugCTA";
|
||||
import { showDebugger } from "actions/debuggerActions";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import type { InteractionAnalyticsEventDetail } from "utils/AppsmithUtils";
|
||||
import {
|
||||
interactionAnalyticsEvent,
|
||||
|
|
@ -106,7 +105,6 @@ const useDependencyList = (name: string) => {
|
|||
(state: AppState) => state.evaluations.dependencies.inverseDependencyMap,
|
||||
equal,
|
||||
);
|
||||
const guidedTour = useSelector(inGuidedTour);
|
||||
|
||||
const getEntityId = useCallback(
|
||||
(name) => {
|
||||
|
|
@ -122,9 +120,8 @@ const useDependencyList = (name: string) => {
|
|||
);
|
||||
|
||||
const entityDependencies = useMemo(() => {
|
||||
if (guidedTour) return null;
|
||||
return getDependenciesFromInverseDependencies(inverseDependencyMap, name);
|
||||
}, [name, inverseDependencyMap, guidedTour]);
|
||||
}, [name, inverseDependencyMap]);
|
||||
|
||||
const dependencyOptions = useMemo(
|
||||
() =>
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@ import { useToggleEditWidgetName } from "utils/hooks/dragResizeHooks";
|
|||
import useInteractionAnalyticsEvent from "utils/hooks/useInteractionAnalyticsEvent";
|
||||
|
||||
import type { WidgetType } from "constants/WidgetConstants";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import { toggleShowDeviationDialog } from "actions/onboardingActions";
|
||||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
import { getIsCurrentWidgetRecentlyAdded } from "selectors/propertyPaneSelectors";
|
||||
|
||||
|
|
@ -63,7 +61,6 @@ const PropertyPaneTitle = memo(function PropertyPaneTitle(
|
|||
const isCurrentWidgetRecentlyAdded = useSelector(
|
||||
getIsCurrentWidgetRecentlyAdded,
|
||||
);
|
||||
const guidedTourEnabled = useSelector(inGuidedTour);
|
||||
|
||||
const { dispatchInteractionAnalyticsEvent, eventEmitterRef } =
|
||||
useInteractionAnalyticsEvent<HTMLDivElement>();
|
||||
|
|
@ -79,11 +76,6 @@ const PropertyPaneTitle = memo(function PropertyPaneTitle(
|
|||
const { title, updatePropertyTitle } = props;
|
||||
const updateNewTitle = useCallback(
|
||||
(value: string) => {
|
||||
if (guidedTourEnabled) {
|
||||
dispatch(toggleShowDeviationDialog(true));
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
value &&
|
||||
value.trim().length > 0 &&
|
||||
|
|
@ -92,16 +84,12 @@ const PropertyPaneTitle = memo(function PropertyPaneTitle(
|
|||
updatePropertyTitle && updatePropertyTitle(value.trim());
|
||||
}
|
||||
},
|
||||
[updatePropertyTitle, title, guidedTourEnabled],
|
||||
[updatePropertyTitle, title],
|
||||
);
|
||||
// End
|
||||
|
||||
const updateTitle = useCallback(
|
||||
(value?: string) => {
|
||||
if (guidedTourEnabled) {
|
||||
dispatch(toggleShowDeviationDialog(true));
|
||||
return;
|
||||
}
|
||||
if (
|
||||
value &&
|
||||
value.trim().length > 0 &&
|
||||
|
|
@ -117,14 +105,7 @@ const PropertyPaneTitle = memo(function PropertyPaneTitle(
|
|||
toggleEditWidgetName(props.widgetId, false);
|
||||
}
|
||||
},
|
||||
[
|
||||
dispatch,
|
||||
widgets,
|
||||
setName,
|
||||
props.widgetId,
|
||||
props.title,
|
||||
guidedTourEnabled,
|
||||
],
|
||||
[dispatch, widgets, setName, props.widgetId, props.title],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -64,8 +64,6 @@ import type { Plugin } from "api/PluginApi";
|
|||
import { UIComponentTypes } from "api/PluginApi";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { DEBUGGER_TAB_KEYS } from "components/editorComponents/Debugger/helpers";
|
||||
import Guide from "pages/Editor/GuidedTour/Guide";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import { EDITOR_TABS, SQL_DATASOURCES } from "constants/QueryEditorConstants";
|
||||
import type { FormEvalOutput } from "reducers/evaluationReducers/formEvaluationReducer";
|
||||
import { isValidFormConfig } from "reducers/evaluationReducers/formEvaluationReducer";
|
||||
|
|
@ -329,7 +327,6 @@ export function EditorJSONtoForm(props: Props) {
|
|||
const actions: Action[] = useSelector((state: AppState) =>
|
||||
state.entities.actions.map((action) => action.config),
|
||||
);
|
||||
const guidedTourEnabled = useSelector(inGuidedTour);
|
||||
const currentActionConfig: Action | undefined = actions.find(
|
||||
(action) => action.id === params.apiId || action.id === params.queryId,
|
||||
);
|
||||
|
|
@ -619,7 +616,8 @@ export function EditorJSONtoForm(props: Props) {
|
|||
// here we check for normal conditions for opening action pane
|
||||
// or if any of the flags are true, We should open the actionpane by default.
|
||||
const shouldOpenActionPaneByDefault =
|
||||
((hasDependencies || !!actionResponse) && !guidedTourEnabled) ||
|
||||
hasDependencies ||
|
||||
!!actionResponse ||
|
||||
currentActionPluginName !== PluginName.SMTP;
|
||||
|
||||
// Datasource selection is hidden for Appsmith AI Plugin and for plugins that don't require datasource
|
||||
|
|
@ -635,8 +633,7 @@ export function EditorJSONtoForm(props: Props) {
|
|||
|
||||
return (
|
||||
<>
|
||||
{!guidedTourEnabled && closeEditorLink}
|
||||
{guidedTourEnabled && <Guide className="query-page" />}
|
||||
{closeEditorLink}
|
||||
<QueryFormContainer onSubmit={handleSubmit(noop)}>
|
||||
<StyledFormRow>
|
||||
<NameWrapper>
|
||||
|
|
|
|||
|
|
@ -9,12 +9,10 @@ import { getAppMode } from "@appsmith/selectors/applicationSelectors";
|
|||
import { setPreviewModeInitAction } from "actions/editorActions";
|
||||
import { previewModeSelector } from "selectors/editorSelectors";
|
||||
|
||||
import { isExploringSelector } from "selectors/onboardingSelectors";
|
||||
import { createMessage, EDITOR_HEADER } from "@appsmith/constants/messages";
|
||||
|
||||
function ToggleModeButton() {
|
||||
const dispatch = useDispatch();
|
||||
const isExploring = useSelector(isExploringSelector);
|
||||
const isPreviewMode = useSelector(previewModeSelector);
|
||||
const appMode = useSelector(getAppMode);
|
||||
|
||||
|
|
@ -25,7 +23,7 @@ function ToggleModeButton() {
|
|||
dispatch(setPreviewModeInitAction(!isPreviewMode));
|
||||
}, [dispatch, setPreviewModeInitAction, isPreviewMode]);
|
||||
|
||||
if (isExploring || isViewMode) return null;
|
||||
if (isViewMode) return null;
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ import {
|
|||
} from "@appsmith/selectors/applicationSelectors";
|
||||
import { setCanvasSelectionFromEditor } from "actions/canvasSelectionActions";
|
||||
import { useAllowEditorDragToSelect } from "utils/hooks/useAllowEditorDragToSelect";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import EditorContextProvider from "components/editorComponents/EditorContextProvider";
|
||||
import Guide from "../GuidedTour/Guide";
|
||||
import MainContainerWrapper from "./MainContainerWrapper";
|
||||
import EmptyCanvasPrompts from "./EmptyCanvasPrompts";
|
||||
import { useAutoHeightUIState } from "utils/hooks/autoHeightUIHooks";
|
||||
|
|
@ -56,7 +54,6 @@ function WidgetsEditor() {
|
|||
const currentPageId = useSelector(getCurrentPageId);
|
||||
const currentPageName = useSelector(getCurrentPageName);
|
||||
const currentApp = useSelector(getCurrentApplication);
|
||||
const guidedTourEnabled = useSelector(inGuidedTour);
|
||||
const isPreviewMode = useSelector(previewModeSelector);
|
||||
const isProtectedMode = useSelector(protectedModeSelector);
|
||||
const lastUpdatedTime = useSelector(getSnapshotUpdatedTime);
|
||||
|
|
@ -164,7 +161,7 @@ function WidgetsEditor() {
|
|||
);
|
||||
|
||||
const showNavigation = () => {
|
||||
if (isPreviewingNavigation && !guidedTourEnabled) {
|
||||
if (isPreviewingNavigation) {
|
||||
return (
|
||||
<NavigationPreview
|
||||
isAppSettingsPaneWithNavigationTabOpen={
|
||||
|
|
@ -179,7 +176,6 @@ function WidgetsEditor() {
|
|||
PerformanceTracker.stopTracking();
|
||||
return (
|
||||
<EditorContextProvider renderMode="CANVAS">
|
||||
{guidedTourEnabled && <Guide />}
|
||||
<div className="relative flex flex-row w-full overflow-hidden">
|
||||
<div
|
||||
className={classNames({
|
||||
|
|
|
|||
|
|
@ -8,13 +8,10 @@ import {
|
|||
COMING_SOON,
|
||||
COMMIT_CHANGES,
|
||||
CONFLICTS_FOUND,
|
||||
CONNECT_GIT,
|
||||
CONNECT_GIT_BETA,
|
||||
CONNECTING_TO_REPO_DISABLED,
|
||||
CONTACT_ADMIN_FOR_GIT,
|
||||
createMessage,
|
||||
DISCARD_AND_PULL_SUCCESS,
|
||||
DURING_ONBOARDING_TOUR,
|
||||
GIT_SETTINGS,
|
||||
MERGE,
|
||||
NO_COMMITS_TO_PULL,
|
||||
|
|
@ -42,7 +39,6 @@ import {
|
|||
protectedModeSelector,
|
||||
} from "selectors/gitSyncSelectors";
|
||||
import SpinnerLoader from "pages/common/SpinnerLoader";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import { getTypographyByKey } from "design-system-old";
|
||||
import { Button, Icon, Tooltip } from "design-system";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
|
|
@ -231,16 +227,6 @@ const StyledIcon = styled(Icon)`
|
|||
margin-right: ${(props) => props.theme.spaces[3]}px;
|
||||
`;
|
||||
|
||||
const PlaceholderButton = styled.div`
|
||||
padding: ${(props) =>
|
||||
`${props.theme.spaces[1]}px ${props.theme.spaces[3]}px`};
|
||||
border: solid 1px ${Colors.MERCURY};
|
||||
${getTypographyByKey("btnSmall")};
|
||||
text-transform: uppercase;
|
||||
background-color: ${Colors.ALABASTER_ALT};
|
||||
color: ${Colors.GRAY};
|
||||
`;
|
||||
|
||||
const OuterContainer = styled.div`
|
||||
padding: 4px 16px;
|
||||
height: 100%;
|
||||
|
|
@ -252,31 +238,20 @@ const CenterDiv = styled.div`
|
|||
|
||||
function ConnectGitPlaceholder() {
|
||||
const dispatch = useDispatch();
|
||||
const isInGuidedTour = useSelector(inGuidedTour);
|
||||
const isConnectToGitPermitted = useHasConnectToGitPermission();
|
||||
|
||||
const isTooltipEnabled = isInGuidedTour || !isConnectToGitPermitted;
|
||||
const isTooltipEnabled = !isConnectToGitPermitted;
|
||||
const tooltipContent = useMemo(() => {
|
||||
if (!isConnectToGitPermitted) {
|
||||
return <CenterDiv>{createMessage(CONTACT_ADMIN_FOR_GIT)}</CenterDiv>;
|
||||
}
|
||||
if (isInGuidedTour) {
|
||||
return (
|
||||
<>
|
||||
<div>{createMessage(CONNECTING_TO_REPO_DISABLED)}</div>
|
||||
<div>{createMessage(DURING_ONBOARDING_TOUR)}</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div>{createMessage(NOT_LIVE_FOR_YOU_YET)}</div>
|
||||
<div>{createMessage(COMING_SOON)}</div>
|
||||
</>
|
||||
);
|
||||
}, [isInGuidedTour, isConnectToGitPermitted]);
|
||||
|
||||
const isGitConnectionEnabled = !isInGuidedTour;
|
||||
}, [isConnectToGitPermitted]);
|
||||
|
||||
return (
|
||||
<OuterContainer>
|
||||
|
|
@ -287,32 +262,26 @@ function ConnectGitPlaceholder() {
|
|||
name="git-commit"
|
||||
size="lg"
|
||||
/>
|
||||
{isGitConnectionEnabled ? (
|
||||
<Button
|
||||
className="t--connect-git-bottom-bar"
|
||||
isDisabled={!isConnectToGitPermitted}
|
||||
kind="secondary"
|
||||
onClick={() => {
|
||||
AnalyticsUtil.logEvent("GS_CONNECT_GIT_CLICK", {
|
||||
source: "BOTTOM_BAR_GIT_CONNECT_BUTTON",
|
||||
});
|
||||
<Button
|
||||
className="t--connect-git-bottom-bar"
|
||||
isDisabled={!isConnectToGitPermitted}
|
||||
kind="secondary"
|
||||
onClick={() => {
|
||||
AnalyticsUtil.logEvent("GS_CONNECT_GIT_CLICK", {
|
||||
source: "BOTTOM_BAR_GIT_CONNECT_BUTTON",
|
||||
});
|
||||
|
||||
dispatch(
|
||||
setIsGitSyncModalOpen({
|
||||
isOpen: true,
|
||||
tab: GitSyncModalTab.GIT_CONNECTION,
|
||||
}),
|
||||
);
|
||||
}}
|
||||
size="sm"
|
||||
>
|
||||
{createMessage(CONNECT_GIT_BETA)}
|
||||
</Button>
|
||||
) : (
|
||||
<PlaceholderButton className="t--disabled-connect-git-bottom-bar">
|
||||
{createMessage(CONNECT_GIT)}
|
||||
</PlaceholderButton>
|
||||
)}
|
||||
dispatch(
|
||||
setIsGitSyncModalOpen({
|
||||
isOpen: true,
|
||||
tab: GitSyncModalTab.GIT_CONNECTION,
|
||||
}),
|
||||
);
|
||||
}}
|
||||
size="sm"
|
||||
>
|
||||
{createMessage(CONNECT_GIT_BETA)}
|
||||
</Button>
|
||||
</Container>
|
||||
</Tooltip>
|
||||
</OuterContainer>
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ import DisconnectGitModal from "pages/Editor/gitSync/DisconnectGitModal";
|
|||
import { setupPage, updateCurrentPage } from "actions/pageActions";
|
||||
import { getCurrentPageId } from "selectors/editorSelectors";
|
||||
import { getSearchQuery } from "utils/helpers";
|
||||
import { loading } from "selectors/onboardingSelectors";
|
||||
import GuidedTourModal from "./GuidedTour/DeviationModal";
|
||||
import RepoLimitExceededErrorModal from "./gitSync/RepoLimitExceededErrorModal";
|
||||
import ImportedApplicationSuccessModal from "./gitSync/ImportedAppSuccessModal";
|
||||
import { getIsBranchUpdated } from "../utils";
|
||||
|
|
@ -171,7 +169,6 @@ class Editor extends Component<Props> {
|
|||
<GitSettingsModal />
|
||||
<DisconnectGitModal />
|
||||
<DisableAutocommitModal />
|
||||
<GuidedTourModal />
|
||||
<RepoLimitExceededErrorModal />
|
||||
<TemplatesModal />
|
||||
<ImportedApplicationSuccessModal />
|
||||
|
|
@ -196,7 +193,6 @@ const mapStateToProps = (state: AppState) => ({
|
|||
user: getCurrentUser(state),
|
||||
currentApplicationName: state.ui.applications.currentApplication?.name,
|
||||
currentPageId: getCurrentPageId(state),
|
||||
loadingGuidedTour: loading(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: any) => {
|
||||
|
|
|
|||
|
|
@ -1,146 +0,0 @@
|
|||
import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants";
|
||||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
import { createReducer } from "utils/ReducerUtils";
|
||||
|
||||
const initialState: GuidedTourState = {
|
||||
guidedTour: false,
|
||||
loading: false,
|
||||
exploring: false,
|
||||
currentStep: 1,
|
||||
showSuccessMessage: false,
|
||||
showInfoMessage: false,
|
||||
tableWidgetWasSelected: false,
|
||||
hadReachedStep: 0,
|
||||
showEndTourDialog: false,
|
||||
showDeviatingDialog: false,
|
||||
showPostCompletionMessage: false,
|
||||
forceShowContent: 0,
|
||||
};
|
||||
|
||||
export interface GuidedTourState {
|
||||
guidedTour: boolean;
|
||||
loading: boolean;
|
||||
exploring: boolean;
|
||||
currentStep: number;
|
||||
showSuccessMessage: boolean;
|
||||
showInfoMessage: boolean;
|
||||
tableWidgetWasSelected: boolean;
|
||||
hadReachedStep: number;
|
||||
showEndTourDialog: boolean;
|
||||
showDeviatingDialog: boolean;
|
||||
showPostCompletionMessage: boolean;
|
||||
forceShowContent: number;
|
||||
}
|
||||
|
||||
const guidedTourReducer = createReducer(initialState, {
|
||||
[ReduxActionTypes.ENABLE_GUIDED_TOUR]: (
|
||||
state: GuidedTourState,
|
||||
action: ReduxAction<boolean>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
...initialState,
|
||||
guidedTour: action.payload,
|
||||
exploring: action.payload,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.GUIDED_TOUR_TOGGLE_LOADER]: (
|
||||
state: GuidedTourState,
|
||||
action: ReduxAction<boolean>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
loading: action.payload,
|
||||
exploring: !action.payload ? false : state.exploring,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.SET_CURRENT_STEP]: (
|
||||
state: GuidedTourState,
|
||||
action: ReduxAction<number>,
|
||||
) => {
|
||||
if (action.payload === state.currentStep) {
|
||||
return state;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
currentStep: action.payload,
|
||||
showSuccessMessage: false,
|
||||
showInfoMessage: false,
|
||||
hadReachedStep:
|
||||
action.payload > state.hadReachedStep
|
||||
? action.payload
|
||||
: state.hadReachedStep,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.SHOW_INFO_MESSAGE]: (state: GuidedTourState) => {
|
||||
return {
|
||||
...state,
|
||||
showInfoMessage: true,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.GUIDED_TOUR_MARK_STEP_COMPLETED]: (
|
||||
state: GuidedTourState,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
showSuccessMessage: true,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.TABLE_WIDGET_WAS_SELECTED]: (
|
||||
state: GuidedTourState,
|
||||
action: ReduxAction<boolean>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
tableWidgetWasSelected: action.payload,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.TOGGLE_DEVIATION_DIALOG]: (
|
||||
state: GuidedTourState,
|
||||
action: ReduxAction<boolean>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
showDeviatingDialog: action.payload,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.TOGGLE_END_GUIDED_TOUR_DIALOG]: (
|
||||
state: GuidedTourState,
|
||||
action: ReduxAction<boolean>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
showEndTourDialog: action.payload,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.SHOW_POST_COMPLETION_MESSAGE]: (
|
||||
state: GuidedTourState,
|
||||
action: ReduxAction<boolean>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
showPostCompletionMessage: action.payload,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.FORCE_SHOW_CONTENT]: (
|
||||
state: GuidedTourState,
|
||||
action: ReduxAction<boolean>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
forceShowContent: action.payload,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.LOAD_GUIDED_TOUR]: (
|
||||
state: GuidedTourState,
|
||||
action: ReduxAction<GuidedTourState>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
...action.payload,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default guidedTourReducer;
|
||||
|
|
@ -129,7 +129,6 @@ import { getQueryParams } from "utils/URLUtils";
|
|||
import type { GenerateCRUDEnabledPluginMap, Plugin } from "api/PluginApi";
|
||||
import { getIsGeneratePageInitiator } from "utils/GenerateCrudUtil";
|
||||
import { shouldBeDefined, trimQueryString } from "utils/helpers";
|
||||
import { inGuidedTour } from "selectors/onboardingSelectors";
|
||||
import { updateReplayEntity } from "actions/pageActions";
|
||||
import OAuthApi from "api/OAuthApi";
|
||||
import type { AppState } from "@appsmith/reducers";
|
||||
|
|
@ -317,8 +316,6 @@ export function* addMockDbToDatasources(actionPayload: addMockDb) {
|
|||
const isGeneratePageInitiator =
|
||||
getIsGeneratePageInitiator(isGeneratePageMode);
|
||||
|
||||
const isInGuidedTour: boolean = yield select(inGuidedTour);
|
||||
|
||||
if (isGeneratePageInitiator) {
|
||||
history.push(
|
||||
generateTemplateFormURL({
|
||||
|
|
@ -329,7 +326,7 @@ export function* addMockDbToDatasources(actionPayload: addMockDb) {
|
|||
}),
|
||||
);
|
||||
} else {
|
||||
if (isInGuidedTour || skipRedirection) {
|
||||
if (skipRedirection) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ import {
|
|||
selectCurrentApplicationSlug,
|
||||
} from "selectors/editorSelectors";
|
||||
import { getIsInitialized as getIsViewerInitialized } from "selectors/appViewSelectors";
|
||||
import { enableGuidedTour } from "actions/onboardingActions";
|
||||
import { setPreviewModeAction } from "actions/editorActions";
|
||||
import type { AppEnginePayload } from "entities/Engine";
|
||||
import { PageNotFoundError } from "entities/Engine";
|
||||
|
|
@ -360,8 +359,6 @@ function* resetEditorSaga() {
|
|||
yield put(resetPageList());
|
||||
yield put(resetApplicationWidgets());
|
||||
yield put(resetRecentEntities());
|
||||
// End guided tour once user exits editor
|
||||
yield put(enableGuidedTour(false));
|
||||
// Reset to edit mode once user exits editor
|
||||
// Without doing this if the user creates a new app they
|
||||
// might end up in preview mode if they were in preview mode
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants";
|
||||
import {
|
||||
ReduxActionTypes,
|
||||
WidgetReduxActionTypes,
|
||||
} from "@appsmith/constants/ReduxActionConstants";
|
||||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
import {
|
||||
all,
|
||||
call,
|
||||
|
|
@ -25,371 +22,27 @@ import {
|
|||
import { getCurrentUser } from "selectors/usersSelectors";
|
||||
import history from "utils/history";
|
||||
|
||||
import {
|
||||
getHadReachedStep,
|
||||
getOnboardingWorkspaces,
|
||||
getQueryAction,
|
||||
getSignpostingStepStateByStep,
|
||||
getTableWidget,
|
||||
} from "selectors/onboardingSelectors";
|
||||
import type { Workspaces } from "@appsmith/constants/workspaceConstants";
|
||||
import { getSignpostingStepStateByStep } from "selectors/onboardingSelectors";
|
||||
import {
|
||||
disableStartSignpostingAction,
|
||||
enableGuidedTour,
|
||||
focusWidgetProperty,
|
||||
loadGuidedTour,
|
||||
removeFirstTimeUserOnboardingApplicationId as removeFirstTimeUserOnboardingApplicationIdAction,
|
||||
setCurrentStep,
|
||||
setSignpostingOverlay,
|
||||
showSignpostingTooltip,
|
||||
signpostingStepUpdate,
|
||||
toggleLoader,
|
||||
} from "actions/onboardingActions";
|
||||
import {
|
||||
getCurrentApplicationId,
|
||||
getIsEditorInitialized,
|
||||
} from "selectors/editorSelectors";
|
||||
import type { WidgetProps } from "widgets/BaseWidget";
|
||||
import { getNextWidgetName } from "./WidgetOperationUtils";
|
||||
import WidgetFactory from "WidgetProvider/factory";
|
||||
import { generateReactKey } from "utils/generators";
|
||||
import { RenderModes } from "constants/WidgetConstants";
|
||||
import log from "loglevel";
|
||||
import { getDataTree } from "selectors/dataTreeSelectors";
|
||||
import { getWidgets } from "./selectors";
|
||||
import {
|
||||
clearActionResponse,
|
||||
updateActionData,
|
||||
} from "actions/pluginActionActions";
|
||||
import {
|
||||
importApplication,
|
||||
updateApplicationLayout,
|
||||
} from "@appsmith/actions/applicationActions";
|
||||
import { setPreviewModeAction } from "actions/editorActions";
|
||||
import type { FlattenedWidgetProps } from "WidgetProvider/constants";
|
||||
import type { ActionData } from "@appsmith/reducers/entityReducers/actionsReducer";
|
||||
import { batchUpdateMultipleWidgetProperties } from "actions/controlActions";
|
||||
import {
|
||||
setExplorerActiveAction,
|
||||
setExplorerPinnedAction,
|
||||
} from "actions/explorerActions";
|
||||
import { selectWidgetInitAction } from "actions/widgetSelectionActions";
|
||||
import { hideIndicator } from "pages/Editor/GuidedTour/utils";
|
||||
import { updateWidgetName } from "actions/propertyPaneActions";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import type { DataTree } from "entities/DataTree/dataTreeTypes";
|
||||
import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
|
||||
import type { User } from "constants/userConstants";
|
||||
import { builderURL, queryEditorIdURL } from "@appsmith/RouteBuilder";
|
||||
import { GuidedTourEntityNames } from "pages/Editor/GuidedTour/constants";
|
||||
import type { GuidedTourState } from "reducers/uiReducers/guidedTourReducer";
|
||||
import { sessionStorage } from "utils/localStorage";
|
||||
import { SelectionRequestType } from "sagas/WidgetSelectUtils";
|
||||
import { builderURL } from "@appsmith/RouteBuilder";
|
||||
import type { SIGNPOSTING_STEP } from "pages/Editor/FirstTimeUserOnboarding/Utils";
|
||||
import type { StepState } from "reducers/uiReducers/onBoardingReducer";
|
||||
import { isUndefined } from "lodash";
|
||||
import { isAirgapped } from "@appsmith/utils/airgapHelpers";
|
||||
import { SIGNPOSTING_ANALYTICS_STEP_NAME } from "pages/Editor/FirstTimeUserOnboarding/constants";
|
||||
|
||||
const GUIDED_TOUR_STORAGE_KEY = "GUIDED_TOUR_STORAGE_KEY";
|
||||
|
||||
function* createApplication() {
|
||||
// If we are starting onboarding from the editor wait for the editor to reset.
|
||||
const isEditorInitialised: boolean = yield select(getIsEditorInitialized);
|
||||
let userWorkspaces: Workspaces[] = yield select(getOnboardingWorkspaces);
|
||||
if (isEditorInitialised) {
|
||||
yield take(ReduxActionTypes.RESET_EDITOR_SUCCESS);
|
||||
|
||||
// If we haven't fetched the workspace list yet we wait for it to complete
|
||||
// as we need an workspace where we create an application
|
||||
if (!userWorkspaces.length) {
|
||||
yield take(ReduxActionTypes.FETCH_USER_APPLICATIONS_WORKSPACES_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
userWorkspaces = yield select(getOnboardingWorkspaces);
|
||||
const currentUser: User | undefined = yield select(getCurrentUser);
|
||||
// @ts-expect-error: currentUser can be undefined
|
||||
const currentWorkspaceId = currentUser.currentWorkspaceId;
|
||||
let workspace;
|
||||
if (!currentWorkspaceId) {
|
||||
workspace = userWorkspaces[0];
|
||||
} else {
|
||||
const filteredWorkspaces = userWorkspaces.filter(
|
||||
(workspace: any) => workspace.workspace.id === currentWorkspaceId,
|
||||
);
|
||||
workspace = filteredWorkspaces[0];
|
||||
}
|
||||
|
||||
if (workspace) {
|
||||
const TourAppPromise = import("pages/Editor/GuidedTour/app.json");
|
||||
const TourApp: Awaited<typeof TourAppPromise> = yield TourAppPromise;
|
||||
|
||||
const appFileObject = new File([JSON.stringify(TourApp)], "app.json", {
|
||||
type: "application/json",
|
||||
});
|
||||
yield put(enableGuidedTour(true));
|
||||
yield put(
|
||||
importApplication({
|
||||
workspaceId: workspace.workspace.id,
|
||||
applicationFile: appFileObject,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
yield put(setPreviewModeAction(true));
|
||||
}
|
||||
|
||||
function* syncGuidedTourStateSaga() {
|
||||
const applicationId: string = yield select(getCurrentApplicationId);
|
||||
const guidedTourState: GuidedTourState = yield select(
|
||||
(state) => state.ui.guidedTour,
|
||||
);
|
||||
yield call(
|
||||
sessionStorage.setItem,
|
||||
GUIDED_TOUR_STORAGE_KEY,
|
||||
JSON.stringify({ applicationId, guidedTourState }),
|
||||
);
|
||||
}
|
||||
|
||||
function* loadGuidedTourInitSaga() {
|
||||
const applicationId: string = yield select(getCurrentApplicationId);
|
||||
const guidedTourState: undefined | string = yield call(
|
||||
sessionStorage.getItem,
|
||||
GUIDED_TOUR_STORAGE_KEY,
|
||||
);
|
||||
if (guidedTourState) {
|
||||
const parsedGuidedTourState: {
|
||||
applicationId: string;
|
||||
guidedTourState: GuidedTourState;
|
||||
} = JSON.parse(guidedTourState);
|
||||
|
||||
if (applicationId === parsedGuidedTourState.applicationId) {
|
||||
yield put(loadGuidedTour(parsedGuidedTourState.guidedTourState));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function* setCurrentStepSaga(action: ReduxAction<number>) {
|
||||
const hadReachedStep: number = yield select(getHadReachedStep);
|
||||
// Log only once when we reach that step
|
||||
if (action.payload > hadReachedStep) {
|
||||
AnalyticsUtil.logEvent("GUIDED_TOUR_REACHED_STEP", {
|
||||
step: action.payload,
|
||||
});
|
||||
}
|
||||
|
||||
yield call(syncGuidedTourStateSaga);
|
||||
yield put(setCurrentStep(action.payload));
|
||||
}
|
||||
|
||||
function* setUpTourAppSaga() {
|
||||
yield put(setPreviewModeAction(false));
|
||||
// Delete the container widget
|
||||
const widgets: { [widgetId: string]: FlattenedWidgetProps } =
|
||||
yield select(getWidgets);
|
||||
const containerWidget = Object.values(widgets).find(
|
||||
(widget) => widget.type === "CONTAINER_WIDGET",
|
||||
);
|
||||
yield put({
|
||||
type: WidgetReduxActionTypes.WIDGET_DELETE,
|
||||
payload: {
|
||||
widgetId: containerWidget?.widgetId,
|
||||
parentId: containerWidget?.parentId,
|
||||
disallowUndo: true,
|
||||
},
|
||||
});
|
||||
|
||||
yield delay(500);
|
||||
// @ts-expect-error: No type declared for getTableWidgetSelector.
|
||||
const tableWidget = yield select(getTableWidget);
|
||||
yield put(
|
||||
batchUpdateMultipleWidgetProperties([
|
||||
{
|
||||
widgetId: tableWidget.widgetId,
|
||||
updates: {
|
||||
modify: {
|
||||
tableData: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
);
|
||||
// Update getCustomers query body
|
||||
const query: ActionData | undefined = yield select(getQueryAction);
|
||||
yield put(clearActionResponse(query?.config.id ?? ""));
|
||||
yield put(
|
||||
updateActionData([
|
||||
{
|
||||
entityName: query?.config.name || "",
|
||||
dataPath: "data",
|
||||
data: undefined,
|
||||
},
|
||||
]),
|
||||
);
|
||||
const applicationId: string = yield select(getCurrentApplicationId);
|
||||
yield put(
|
||||
updateApplicationLayout(applicationId || "", {
|
||||
appLayout: {
|
||||
type: "DESKTOP",
|
||||
},
|
||||
}),
|
||||
);
|
||||
if (!query) return;
|
||||
history.push(
|
||||
queryEditorIdURL({
|
||||
pageId: query.config.pageId,
|
||||
queryId: query.config.id,
|
||||
}),
|
||||
);
|
||||
// Hide the explorer initialy
|
||||
yield put(setExplorerPinnedAction(false));
|
||||
yield put(setExplorerActiveAction(false));
|
||||
yield put(toggleLoader(false));
|
||||
}
|
||||
|
||||
function* addOnboardingWidget(action: ReduxAction<Partial<WidgetProps>>) {
|
||||
const widgetConfig = action.payload;
|
||||
|
||||
if (!widgetConfig.type) return;
|
||||
|
||||
const defaultConfig = WidgetFactory.widgetConfigMap.get(widgetConfig.type);
|
||||
|
||||
const evalTree: DataTree = yield select(getDataTree);
|
||||
const widgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
||||
|
||||
const widgetName = getNextWidgetName(widgets, widgetConfig.type, evalTree, {
|
||||
prefix: widgetConfig.widgetName,
|
||||
});
|
||||
|
||||
try {
|
||||
const newWidget = {
|
||||
newWidgetId: generateReactKey(),
|
||||
widgetId: "0",
|
||||
parentId: "0",
|
||||
renderMode: RenderModes.CANVAS,
|
||||
isLoading: false,
|
||||
...defaultConfig,
|
||||
widgetName,
|
||||
...widgetConfig,
|
||||
};
|
||||
|
||||
yield put({
|
||||
type: WidgetReduxActionTypes.WIDGET_ADD_CHILD,
|
||||
payload: newWidget,
|
||||
});
|
||||
|
||||
// Wait for widget names to be updated
|
||||
// Updating widget names here as widget blueprints don't take widget names
|
||||
yield take(ReduxActionTypes.SAVE_PAGE_SUCCESS);
|
||||
const widgets: { [widgetId: string]: FlattenedWidgetProps } =
|
||||
yield select(getWidgets);
|
||||
|
||||
const nameInput = Object.values(widgets).find(
|
||||
(widget) => widget.widgetName === "Input1",
|
||||
);
|
||||
const emailInput = Object.values(widgets).find(
|
||||
(widget) => widget.widgetName === "Input2",
|
||||
);
|
||||
const countryInput = Object.values(widgets).find(
|
||||
(widget) => widget.widgetName === "Input3",
|
||||
);
|
||||
const imageWidget = Object.values(widgets).find(
|
||||
(widget) => widget.widgetName === "Image1",
|
||||
);
|
||||
|
||||
if (nameInput && emailInput && countryInput && imageWidget) {
|
||||
yield put(
|
||||
updateWidgetName(nameInput.widgetId, GuidedTourEntityNames.NAME_INPUT),
|
||||
);
|
||||
yield take(ReduxActionTypes.FETCH_PAGE_DSL_SUCCESS);
|
||||
yield put(
|
||||
updateWidgetName(
|
||||
emailInput.widgetId,
|
||||
GuidedTourEntityNames.EMAIL_INPUT,
|
||||
),
|
||||
);
|
||||
yield take(ReduxActionTypes.FETCH_PAGE_DSL_SUCCESS);
|
||||
yield put(
|
||||
updateWidgetName(
|
||||
countryInput.widgetId,
|
||||
GuidedTourEntityNames.COUNTRY_INPUT,
|
||||
),
|
||||
);
|
||||
yield take(ReduxActionTypes.FETCH_PAGE_DSL_SUCCESS);
|
||||
yield put(
|
||||
updateWidgetName(
|
||||
imageWidget.widgetId,
|
||||
GuidedTourEntityNames.DISPLAY_IMAGE,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Update button widget text
|
||||
function* updateWidgetTextSaga() {
|
||||
const widgets: { [widgetId: string]: FlattenedWidgetProps } =
|
||||
yield select(getWidgets);
|
||||
const buttonWidget = Object.values(widgets).find(
|
||||
(widget) => widget.type === "BUTTON_WIDGET",
|
||||
);
|
||||
if (buttonWidget) {
|
||||
yield put(
|
||||
batchUpdateMultipleWidgetProperties([
|
||||
{
|
||||
widgetId: buttonWidget.widgetId,
|
||||
updates: {
|
||||
modify: {
|
||||
text: "Click to Update",
|
||||
rightColumn: buttonWidget.leftColumn + 24,
|
||||
bottomRow: buttonWidget.topRow + 5,
|
||||
widgetName: GuidedTourEntityNames.BUTTON_WIDGET,
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function* focusWidgetPropertySaga(action: ReduxAction<string>) {
|
||||
const input: HTMLElement | null = document.querySelector(
|
||||
`[data-guided-tour-iid=${action.payload}] .CodeEditorTarget textarea`,
|
||||
);
|
||||
input?.focus();
|
||||
}
|
||||
|
||||
function* endGuidedTourSaga(action: ReduxAction<boolean>) {
|
||||
if (!action.payload) {
|
||||
yield call(hideIndicator);
|
||||
yield call(sessionStorage.removeItem, GUIDED_TOUR_STORAGE_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
function* selectWidgetSaga(
|
||||
action: ReduxAction<{ widgetName: string; propertyName?: string }>,
|
||||
) {
|
||||
const widgets: { [widgetId: string]: FlattenedWidgetProps } =
|
||||
yield select(getWidgets);
|
||||
const widget = Object.values(widgets).find((widget) => {
|
||||
return widget.widgetName === action.payload.widgetName;
|
||||
});
|
||||
|
||||
if (widget) {
|
||||
yield put(
|
||||
selectWidgetInitAction(SelectionRequestType.One, [widget.widgetId]),
|
||||
);
|
||||
// Delay to wait for the fields to render
|
||||
yield delay(1000);
|
||||
// If the propertyName exist then we focus the respective input field as well
|
||||
if (action.payload.propertyName)
|
||||
yield put(focusWidgetProperty(action.payload.propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
// Signposting sagas
|
||||
function* setFirstTimeUserOnboardingApplicationId(action: ReduxAction<string>) {
|
||||
yield storeFirstTimeUserOnboardingApplicationId(action.payload);
|
||||
|
|
@ -528,21 +181,6 @@ function* setSignpostingStepStateSaga(
|
|||
|
||||
export default function* onboardingActionSagas() {
|
||||
yield all([
|
||||
takeLatest(
|
||||
ReduxActionTypes.ONBOARDING_CREATE_APPLICATION,
|
||||
createApplication,
|
||||
),
|
||||
takeLatest(ReduxActionTypes.SET_UP_TOUR_APP, setUpTourAppSaga),
|
||||
takeLatest(ReduxActionTypes.GUIDED_TOUR_ADD_WIDGET, addOnboardingWidget),
|
||||
takeLatest(ReduxActionTypes.SET_CURRENT_STEP_INIT, setCurrentStepSaga),
|
||||
takeLatest(
|
||||
ReduxActionTypes.UPDATE_BUTTON_WIDGET_TEXT,
|
||||
updateWidgetTextSaga,
|
||||
),
|
||||
takeLatest(ReduxActionTypes.ENABLE_GUIDED_TOUR, endGuidedTourSaga),
|
||||
takeLatest(ReduxActionTypes.GUIDED_TOUR_FOCUS_WIDGET, selectWidgetSaga),
|
||||
takeLatest(ReduxActionTypes.FOCUS_WIDGET_PROPERTY, focusWidgetPropertySaga),
|
||||
takeLatest(ReduxActionTypes.LOAD_GUIDED_TOUR_INIT, loadGuidedTourInitSaga),
|
||||
takeLatest(
|
||||
ReduxActionTypes.SET_FIRST_TIME_USER_ONBOARDING_APPLICATION_ID,
|
||||
setFirstTimeUserOnboardingApplicationId,
|
||||
|
|
|
|||
|
|
@ -42,11 +42,6 @@ import {
|
|||
} from "./WidgetOperationUtils";
|
||||
import { showUndoRedoToast } from "utils/replayHelpers";
|
||||
import WidgetFactory from "WidgetProvider/factory";
|
||||
import {
|
||||
inGuidedTour,
|
||||
isExploringSelector,
|
||||
} from "selectors/onboardingSelectors";
|
||||
import { toggleShowDeviationDialog } from "actions/onboardingActions";
|
||||
import { generateAutoHeightLayoutTreeAction } from "actions/autoHeightActions";
|
||||
import { SelectionRequestType } from "sagas/WidgetSelectUtils";
|
||||
import { updateFlexLayersOnDelete } from "../layoutSystems/autolayout/utils/AutoLayoutUtils";
|
||||
|
|
@ -146,13 +141,6 @@ function* deleteSagaInit(deleteAction: ReduxAction<WidgetDelete>) {
|
|||
const selectedWidget: FlattenedWidgetProps | undefined =
|
||||
yield select(getSelectedWidget);
|
||||
const selectedWidgets: string[] = yield select(getSelectedWidgets);
|
||||
const guidedTourEnabled: boolean = yield select(inGuidedTour);
|
||||
const isExploring: boolean = yield select(isExploringSelector);
|
||||
|
||||
if (guidedTourEnabled && !isExploring) {
|
||||
yield put(toggleShowDeviationDialog(true));
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedWidgets.length > 1) {
|
||||
yield put({
|
||||
|
|
|
|||
|
|
@ -1,16 +1,9 @@
|
|||
import { hasCreateNewAppPermission } from "@appsmith/utils/permissionHelpers";
|
||||
import type { AppState } from "@appsmith/reducers";
|
||||
import { createSelector } from "reselect";
|
||||
import { getUserApplicationsWorkspaces } from "@appsmith/selectors/applicationSelectors";
|
||||
import { getWidgets } from "sagas/selectors";
|
||||
import {
|
||||
getActionResponses,
|
||||
getActions,
|
||||
getCurrentActions,
|
||||
getCanvasWidgets,
|
||||
} from "@appsmith/selectors/entitiesSelector";
|
||||
import { getLastSelectedWidget } from "./ui";
|
||||
import { GuidedTourEntityNames } from "pages/Editor/GuidedTour/constants";
|
||||
import type { SIGNPOSTING_STEP } from "pages/Editor/FirstTimeUserOnboarding/Utils";
|
||||
import { isBoolean, intersection } from "lodash";
|
||||
import { getEvaluationInverseDependencyMap } from "./dataTreeSelectors";
|
||||
|
|
@ -41,9 +34,6 @@ export const getIsFirstTimeUserOnboardingEnabled = createSelector(
|
|||
export const getInOnboardingWidgetSelection = (state: AppState) =>
|
||||
state.ui.onBoarding.inOnboardingWidgetSelection;
|
||||
|
||||
export const getIsOnboardingWidgetSelection = (state: AppState) =>
|
||||
state.ui.onBoarding.inOnboardingWidgetSelection;
|
||||
|
||||
export const getSignpostingStepState = (state: AppState) =>
|
||||
state.ui.onBoarding.stepState;
|
||||
export const getSignpostingStepStateByStep = createSelector(
|
||||
|
|
@ -98,249 +88,3 @@ export const isWidgetActionConnectionPresent = createSelector(
|
|||
return isBindingAvailable;
|
||||
},
|
||||
);
|
||||
|
||||
// Guided Tour selectors
|
||||
export const isExploringSelector = (state: AppState) =>
|
||||
state.ui.guidedTour.exploring;
|
||||
export const inGuidedTour = (state: AppState) => state.ui.guidedTour.guidedTour;
|
||||
export const getCurrentStep = (state: AppState) =>
|
||||
state.ui.guidedTour.currentStep;
|
||||
export const wasTableWidgetSelected = (state: AppState) =>
|
||||
state.ui.guidedTour.tableWidgetWasSelected;
|
||||
export const showEndTourDialogSelector = (state: AppState) =>
|
||||
state.ui.guidedTour.showEndTourDialog;
|
||||
export const showDeviatingDialogSelector = (state: AppState) =>
|
||||
state.ui.guidedTour.showDeviatingDialog;
|
||||
export const showPostCompletionMessage = (state: AppState) =>
|
||||
state.ui.guidedTour.showPostCompletionMessage;
|
||||
export const forceShowContentSelector = (state: AppState) =>
|
||||
state.ui.guidedTour.forceShowContent;
|
||||
|
||||
export const getTableWidget = createSelector(getWidgets, (widgets) => {
|
||||
return Object.values(widgets).find(
|
||||
(widget) => widget.widgetName === "CustomersTable",
|
||||
);
|
||||
});
|
||||
|
||||
export const getQueryAction = createSelector(getActions, (actions) => {
|
||||
return actions.find((action) => {
|
||||
return action.config.name === "getCustomers";
|
||||
});
|
||||
});
|
||||
|
||||
export const isQueryLimitUpdated = createSelector(getQueryAction, (query) => {
|
||||
if (query) {
|
||||
let body = query.config.actionConfiguration.body;
|
||||
if (body) {
|
||||
// eslint-disable-next-line no-console
|
||||
const regex = /SELECT \* FROM user_data ORDER BY id LIMIT 10;/gi;
|
||||
// Replacing new line characters
|
||||
body = body.replace(/(?:\r\n|\r|\n)/g, "");
|
||||
// Replace sql comments
|
||||
body = body.replace(/(\/\*[^*]*\*\/)|(\/\/[^*]*)|(--[^.].*)/gm, "");
|
||||
return regex.test(body);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
export const isQueryExecutionSuccessful = createSelector(
|
||||
getActionResponses,
|
||||
getQueryAction,
|
||||
(responses, query) => {
|
||||
if (query?.config.id && responses[query.config.id]) {
|
||||
return responses[query.config.id]?.isExecutionSuccess;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export const isTableWidgetSelected = createSelector(
|
||||
getTableWidget,
|
||||
getLastSelectedWidget,
|
||||
wasTableWidgetSelected,
|
||||
(tableWidget, selectedWidgetId, tableWidgetWasSelected) => {
|
||||
if (!tableWidgetWasSelected) {
|
||||
return tableWidget?.widgetId === selectedWidgetId;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
);
|
||||
|
||||
export const tableWidgetHasBinding = createSelector(
|
||||
getTableWidget,
|
||||
(tableWidget) => {
|
||||
if (tableWidget) {
|
||||
if (tableWidget.tableData === `{{getCustomers.data}}`) {
|
||||
return tableWidget.widgetId;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
},
|
||||
);
|
||||
|
||||
export const containerWidgetAdded = createSelector(getWidgets, (widgets) => {
|
||||
return !!Object.values(widgets).find(
|
||||
(widget) => widget.type === "CONTAINER_WIDGET",
|
||||
);
|
||||
});
|
||||
|
||||
export const getHadReachedStep = (state: AppState) =>
|
||||
state.ui.guidedTour.hadReachedStep;
|
||||
|
||||
export const isNameInputBoundSelector = createSelector(
|
||||
getTableWidget,
|
||||
getWidgets,
|
||||
(tableWidget, widgets) => {
|
||||
if (tableWidget) {
|
||||
const widgetValues = Object.values(widgets);
|
||||
const countryInput = widgetValues.find((widget) => {
|
||||
if (widget.type === "INPUT_WIDGET_V2") {
|
||||
return (
|
||||
widget.defaultText ===
|
||||
`{{${tableWidget.widgetName}.selectedRow.name}}`
|
||||
);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (countryInput) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
);
|
||||
|
||||
// Get the id of NameInput
|
||||
export const nameInputSelector = createSelector(getWidgets, (widgets) => {
|
||||
const widgetValues = Object.values(widgets);
|
||||
const nameInput = widgetValues.find((widget) => {
|
||||
if (widget.type === "INPUT_WIDGET_V2") {
|
||||
return widget.widgetName === "NameInput";
|
||||
}
|
||||
});
|
||||
|
||||
return nameInput ? nameInput.widgetId : "";
|
||||
});
|
||||
// Check if CountryInput is selected
|
||||
export const countryInputSelector = createSelector(
|
||||
getWidgets,
|
||||
getLastSelectedWidget,
|
||||
(widgets, selectedWidgetId) => {
|
||||
const widgetValues = Object.values(widgets);
|
||||
const countryInput = widgetValues.find((widget) => {
|
||||
if (widget.type === "INPUT_WIDGET_V2") {
|
||||
return widget.widgetName === "CountryInput";
|
||||
}
|
||||
});
|
||||
|
||||
return countryInput ? countryInput.widgetId === selectedWidgetId : false;
|
||||
},
|
||||
);
|
||||
|
||||
export const isCountryInputBound = createSelector(
|
||||
getTableWidget,
|
||||
getWidgets,
|
||||
(tableWidget, widgets) => {
|
||||
if (tableWidget) {
|
||||
const widgetValues = Object.values(widgets);
|
||||
const countryInput = widgetValues.find((widget) => {
|
||||
if (widget.widgetName === GuidedTourEntityNames.COUNTRY_INPUT) {
|
||||
return (
|
||||
widget.defaultText ===
|
||||
`{{${tableWidget.widgetName}.selectedRow.country}}`
|
||||
);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (countryInput) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
);
|
||||
|
||||
export const isEmailInputBound = createSelector(
|
||||
getTableWidget,
|
||||
getWidgets,
|
||||
(tableWidget, widgets) => {
|
||||
if (tableWidget) {
|
||||
const widgetValues = Object.values(widgets);
|
||||
const countryInput = widgetValues.find((widget) => {
|
||||
if (widget.widgetName === GuidedTourEntityNames.EMAIL_INPUT) {
|
||||
return (
|
||||
widget.defaultText ===
|
||||
`{{${tableWidget.widgetName}.selectedRow.email}}`
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (countryInput) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
);
|
||||
|
||||
export const isButtonWidgetPresent = createSelector(getWidgets, (widgets) => {
|
||||
const widgetValues = Object.values(widgets);
|
||||
const buttonWidget = widgetValues.find((widget) => {
|
||||
return widget.type === "BUTTON_WIDGET";
|
||||
});
|
||||
|
||||
return !!buttonWidget;
|
||||
});
|
||||
|
||||
export const buttonWidgetHasOnClickBinding = createSelector(
|
||||
getWidgets,
|
||||
(widgets) => {
|
||||
const widgetValues = Object.values(widgets);
|
||||
const buttonWidget = widgetValues.find((widget) => {
|
||||
return (
|
||||
widget.type === "BUTTON_WIDGET" &&
|
||||
widget.onClick &&
|
||||
widget.onClick.includes("{{updateCustomerInfo.run(")
|
||||
);
|
||||
});
|
||||
|
||||
return !!buttonWidget;
|
||||
},
|
||||
);
|
||||
|
||||
export const buttonWidgetHasOnSuccessBinding = createSelector(
|
||||
getWidgets,
|
||||
(widgets) => {
|
||||
const widgetValues = Object.values(widgets);
|
||||
const buttonWidget = widgetValues.find((widget) => {
|
||||
return (
|
||||
widget.type === "BUTTON_WIDGET" &&
|
||||
widget.onClick &&
|
||||
widget.onClick.includes("getCustomers.run()")
|
||||
);
|
||||
});
|
||||
|
||||
return !!buttonWidget;
|
||||
},
|
||||
);
|
||||
|
||||
export const showSuccessMessage = (state: AppState) =>
|
||||
state.ui.guidedTour.showSuccessMessage;
|
||||
export const showInfoMessageSelector = (state: AppState) =>
|
||||
state.ui.guidedTour.showInfoMessage;
|
||||
|
||||
export const loading = (state: AppState) => state.ui.guidedTour.loading;
|
||||
|
||||
// To find an workspace where the user has permission to create an
|
||||
// application
|
||||
export const getOnboardingWorkspaces = createSelector(
|
||||
getUserApplicationsWorkspaces,
|
||||
(userWorkspaces) => {
|
||||
return userWorkspaces.filter((userWorkspace) =>
|
||||
hasCreateNewAppPermission(userWorkspace.workspace.userPermissions ?? []),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ export const STORAGE_KEYS: {
|
|||
ROUTE_BEFORE_LOGIN: "RedirectPath",
|
||||
COPIED_WIDGET: "CopiedWidget",
|
||||
GROUP_COPIED_WIDGETS: "groupCopiedWidgets",
|
||||
POST_WELCOME_TOUR: "PostWelcomeTour",
|
||||
RECENT_ENTITIES: "RecentEntities",
|
||||
TEMPLATES_NOTIFICATION_SEEN: "TEMPLATES_NOTIFICATION_SEEN",
|
||||
ONBOARDING_FORM_IN_PROGRESS: "ONBOARDING_FORM_IN_PROGRESS",
|
||||
|
|
@ -195,24 +194,6 @@ export const resetCurrentEnvironment = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
export const setPostWelcomeTourState = async (flag: boolean) => {
|
||||
try {
|
||||
await store.setItem(STORAGE_KEYS.POST_WELCOME_TOUR, flag);
|
||||
return true;
|
||||
} catch (error) {
|
||||
log.error("An error occurred when setting post welcome tour state", error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const getPostWelcomeTourState = async () => {
|
||||
try {
|
||||
return await store.getItem(STORAGE_KEYS.POST_WELCOME_TOUR);
|
||||
} catch (error) {
|
||||
log.error("An error occurred when getting post welcome tour state", error);
|
||||
}
|
||||
};
|
||||
|
||||
export const setRecentAppEntities = async (entities: any, appId: string) => {
|
||||
try {
|
||||
const recentEntities =
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user