PromucFlow_constructor/app/client/src/sagas/OnboardingSagas.ts
Pawan Kumar 8395f5e18f
feat: property pane docking (#7361)
* add tailwindcss

* docked property pane

* uncomment a line

* make entity explorer as drawer on unpin

* remove unused imports

* add pin state in  reducer

* add menu icon in header

* fix widget sidebar

* fix widgets sidebar

* style property pane

* update property pane css

* update icons in property pane

* update property pane header styles

* update spacing

* fix few ui issues

* wip: preview mode

* wip:preview mode

* remove unused import

* comments sidebar in app and edit mode

* fix order of import

* use selected state for property pane

* update scrollbar style

* add classes to sidebar and property pane

* make widgets editor fluid

* make widgets editor fluid and refactor logic

* resize the widgets editor if explorer is pinned

* add shortcut for preview mode

* fix link for tabs in edit mode

* zoom in/zoom out for 0.75

* fix chart widget + table widget crashing

* allow zooming of canvas

* fix weird canvas draw issue + update container for handling zoom

* add actions for is panning

* allow panning with grab cursor

* reset panning + zooming when entering preview mode

* add grabbing cursor when grabbing

* only prevent default when space key is pressed

* dont allow zoom in preview mode

* remove unused imports

* fix dont allow zoom in preview mode

* fix ux of panning on space hit

* make fluid as the default app layout

* chart spec

* fix dropdown_on change spec

* fix add widget table and bind spec

* remove draggable property pane spec

* fix container spec

* fix form widget spec

* fix jest test

* fix the function typo

* remove clicking of close button for property pane in cypress tests

* remove property pane actions test

* fix drag and drop test failing

* add cypress selector id to back button in property pane

* fix toggle js spec

* fix merge conflicts from new design system

* editor header

* fix product updates styles + widget card

* remove all unused imports

* fix dynamic layout spec

* fix entity explorer tab rename test failing

* fix table spec

* fix bind tabletextpagination spec

* fix js object spec

* fix entity explorer rename issue

* fix cypress test

* fix cypress command wrong commit

* fix tab spec

* fix property pane copy tests

* add zoom header

* zoom levels

* make property pane sidebar resizable

* add multi select property pane

* fix widget search bug

* update property pane width in state on drag end

* fix viewer header

* fix editor header

* update editor header + remove zooming

* update small style

* dont allow closing of explorer when resizing

* fix jest test

* fix dropdown widget jest test

* preview test case wip

* add entity explorer pinning tests + preview mode tests

* add tooltip in layout control + add padding bottom in property pane view

* incorporate aakash feedbacks

* fix preview mode margin issue

* remove panning code

* fix cypress failing test

* uncomment jest test

* remove redundant code

* fix maincontainer test

* incorporate review feedbacks

* incorporate aakash feedbacks

* review feedbacks

* incorporate review feedbacks

* incorporate qa feedbacks

* fix dynamic layout spec

* updated test based on latest change

* dsl updated

* Updated dsl

* Updated dsl

* resize deselects widget issue.

* fix canvas height issue

* fix typo

* incorporate qa feedbacks

* incorporate qa feedbacks

* incorporate qa feedbacks

* update color for setting control for widget name

* fix onboarding styles conflicts

* Updated tests

* fix application overflow issue

* updated test method

Co-authored-by: root <root@DESKTOP-9GENCK0.localdomain>
Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro.local>
Co-authored-by: Ashok Kumar M <35134347+marks0351@users.noreply.github.com>
Co-authored-by: Apple <nandan@thinkify.io>
2021-11-23 13:31:46 +05:30

1050 lines
29 KiB
TypeScript

import { GenericApiResponse } from "api/ApiResponses";
import DatasourcesApi from "api/DatasourcesApi";
import { Datasource } from "entities/Datasource";
import { Plugin } from "api/PluginApi";
import {
ReduxAction,
ReduxActionErrorTypes,
ReduxActionTypes,
WidgetReduxActionTypes,
} from "constants/ReduxActionConstants";
import { AppState } from "reducers";
import {
all,
call,
cancel,
delay,
fork,
put,
select,
take,
takeLatest,
} from "redux-saga/effects";
import {
getCanvasWidgets,
getDatasources,
getPlugins,
} from "selectors/entitiesSelector";
import { getDataTree } from "selectors/dataTreeSelectors";
import { getCurrentOrgId } from "selectors/organizationSelectors";
import {
getOnboardingState,
setEnableFirstTimeUserOnboarding as storeEnableFirstTimeUserOnboarding,
setFirstTimeUserOnboardingApplicationId as storeFirstTimeUserOnboardingApplicationId,
setFirstTimeUserOnboardingIntroModalVisibility as storeFirstTimeUserOnboardingIntroModalVisibility,
setOnboardingState,
setOnboardingWelcomeState,
} from "utils/storage";
import { validateResponse } from "./ErrorSagas";
import { getSelectedWidget, getWidgetByName, getWidgets } from "./selectors";
import {
endOnboarding,
setCurrentStep,
setCurrentSubstep,
setHelperConfig,
setOnboardingState as setOnboardingReduxState,
showIndicator,
showOnboardingHelper,
} from "actions/onboardingActions";
import {
changeDatasource,
expandDatasourceEntity,
} from "actions/datasourceActions";
import {
playOnboardingAnimation,
playOnboardingStepCompletionAnimation,
trimQueryString,
} from "utils/helpers";
import {
OnboardingConfig,
OnboardingHelperConfig,
OnboardingStep,
} from "constants/OnboardingConstants";
import AnalyticsUtil from "../utils/AnalyticsUtil";
import { get } from "lodash";
import { AppIconCollection } from "components/ads/AppIcon";
import { getAppCardColorPalette } from "selectors/themeSelectors";
import {
getRandomPaletteColor,
getNextEntityName,
getQueryParams,
} from "utils/AppsmithUtils";
import { getCurrentUser } from "selectors/usersSelectors";
import {
getCurrentApplicationId,
getCurrentPageId,
getIsEditorInitialized,
} from "selectors/editorSelectors";
import { createActionRequest, runAction } from "actions/pluginActionActions";
import {
APPLICATIONS_URL,
BUILDER_PAGE_URL,
INTEGRATION_EDITOR_URL,
INTEGRATION_TABS,
matchBuilderPath,
} from "constants/routes";
import { QueryAction } from "entities/Action";
import history from "utils/history";
import { getQueryIdFromURL } from "pages/Editor/Explorer/helpers";
// import { calculateNewWidgetPosition } from "./WidgetOperationSagas";
import { RenderModes } from "constants/WidgetConstants";
import { generateReactKey } from "utils/generators";
import { navigateToCanvas } from "pages/Editor/Explorer/Widgets/utils";
import {
batchUpdateWidgetProperty,
updateWidgetPropertyRequest,
} from "actions/controlActions";
import OnSubmitGif from "assets/gifs/onsubmit.gif";
import { checkAndGetPluginFormConfigsSaga } from "sagas/PluginSagas";
import WidgetFactory from "utils/WidgetFactory";
const WidgetTypes = WidgetFactory.widgetTypes;
import {
EVAL_ERROR_PATH,
EvaluationError,
PropertyEvaluationErrorType,
} from "utils/DynamicBindingUtils";
import { GRID_DENSITY_MIGRATION_V1 } from "widgets/constants";
import {
getFirstTimeUserOnboardingApplicationId,
getIsFirstTimeUserOnboardingEnabled,
getOnboardingOrganisations,
} from "selectors/onboardingSelectors";
import { Toaster } from "components/ads/Toast";
import { Variant } from "components/ads/common";
import { Organization } from "constants/orgConstants";
export const getCurrentStep = (state: AppState) =>
state.ui.onBoarding.currentStep;
export const getCurrentSubStep = (state: AppState) =>
state.ui.onBoarding.currentSubstep;
export const inOnboarding = (state: AppState) =>
state.ui.onBoarding.inOnboarding;
export const isAddWidgetComplete = (state: AppState) =>
state.ui.onBoarding.addedWidget;
export const showCompletionDialog = (state: AppState) => {
const isInOnboarding = inOnboarding(state);
const currentStep = getCurrentStep(state);
return isInOnboarding && currentStep === OnboardingStep.DEPLOY;
};
export const getInitialTableData = (state: AppState) => {
const widgetConfig = state.entities.widgetConfig;
return widgetConfig.config.TABLE_WIDGET.tableData;
};
export const getHelperConfig = (step: OnboardingStep) => {
return OnboardingConfig[step].helper as OnboardingHelperConfig;
};
export const checkCurrentStep = (
state: AppState,
step: OnboardingStep,
comparison: "EQAULS" | "LESSER" = "EQAULS",
) => {
const isInOnboarding = inOnboarding(state);
const currentStep = getCurrentStep(state);
switch (comparison) {
case "LESSER":
return isInOnboarding && currentStep < step;
default:
return isInOnboarding && currentStep === step;
}
};
function* listenForWidgetAdditions() {
while (true) {
yield take();
const selectedWidget = yield select(getSelectedWidget);
const canvasWidgets = yield select(getCanvasWidgets);
const initialTableData = yield select(getInitialTableData);
// Updating the tableData property to []
if (
selectedWidget &&
selectedWidget.type === "TABLE_WIDGET" &&
canvasWidgets[selectedWidget.widgetId]
) {
if (
selectedWidget.widgetName === "Standup_Table" ||
selectedWidget.tableData === initialTableData
) {
yield put(
batchUpdateWidgetProperty(selectedWidget.widgetId, {
modify: {
widgetName: "Standup_Table",
tableData: [],
columnSizeMap: {
avatar: 80,
name: 120,
},
columnTypeMap: {
avatar: {
type: "image",
format: "",
},
},
migrated: false,
...getStandupTableDimensions(),
},
}),
);
}
AnalyticsUtil.logEvent("ONBOARDING_ADD_WIDGET_TABLE");
yield put(setCurrentStep(OnboardingStep.SUCCESSFUL_BINDING));
yield put({
type: ReduxActionTypes.ADD_WIDGET_COMPLETE,
});
yield put(
setHelperConfig(getHelperConfig(OnboardingStep.SUCCESSFUL_BINDING)),
);
return;
}
}
}
function* listenForAddInputWidget() {
while (true) {
yield take();
const canvasWidgets = yield select(getCanvasWidgets);
const currentPageId = yield select(getCurrentPageId);
const applicationId = yield select(getCurrentApplicationId);
const widgets = yield select(getWidgets);
const inputWidget: any = Object.values(widgets).find(
(widget: any) => widget.type === "INPUT_WIDGET",
);
const isOnBuilder = matchBuilderPath(window.location.pathname);
trimQueryString(
BUILDER_PAGE_URL({
applicationId,
pageId: currentPageId,
}),
);
if (
inputWidget &&
inputWidget.type === "INPUT_WIDGET" &&
canvasWidgets[inputWidget.widgetId]
) {
if (!isOnBuilder) {
yield cancel();
}
AnalyticsUtil.logEvent("ONBOARDING_ADD_WIDGET_INPUT");
if (inputWidget.widgetName !== "Standup_Input") {
yield put(
updateWidgetPropertyRequest(
inputWidget.widgetId,
"widgetName",
"Standup_Input",
),
);
yield put(
batchUpdateWidgetProperty(inputWidget.widgetId, {
modify: {
...getStandupInputDimensions(),
...getStandupInputProps(),
},
}),
);
yield put(setCurrentSubstep(2));
yield put(showIndicator(OnboardingStep.ADD_INPUT_WIDGET));
}
const helperConfig: OnboardingHelperConfig = yield select(
(state) => state.ui.onBoarding.helperStepConfig,
);
const onSubmitGifUrl = OnSubmitGif;
if (helperConfig.image?.src !== onSubmitGifUrl) {
yield put(
setHelperConfig({
...helperConfig,
image: {
src: onSubmitGifUrl,
},
}),
);
}
yield take(ReduxActionTypes.CREATE_ACTION_SUCCESS);
const dataTree = yield select(getDataTree);
const updatedInputWidget = dataTree["Standup_Input"];
if (updatedInputWidget) {
const dynamicTriggerPathList =
updatedInputWidget.dynamicTriggerPathList;
const hasOnSubmitHandler =
dynamicTriggerPathList &&
dynamicTriggerPathList.length &&
dynamicTriggerPathList.some(
(trigger: any) => trigger.key === "onSubmit",
);
if (hasOnSubmitHandler) {
yield put(
updateWidgetPropertyRequest(
inputWidget.widgetId,
"onSubmit",
"{{add_standup_updates.run(() => fetch_standup_updates.run(), () => {})}}",
),
);
AnalyticsUtil.logEvent("ONBOARDING_ONSUBMIT_SUCCESS");
yield put(setCurrentStep(OnboardingStep.DEPLOY));
yield put(setHelperConfig(getHelperConfig(OnboardingStep.DEPLOY)));
return;
}
}
}
}
}
function* listenForSuccessfulBinding() {
while (true) {
yield take();
let bindSuccessful = true;
const selectedWidget = yield call(getStandupTableWidget);
if (selectedWidget && selectedWidget.type === "TABLE_WIDGET") {
const dataTree = yield select(getDataTree);
if (dataTree[selectedWidget.widgetName]) {
const dynamicBindingPathList =
dataTree[selectedWidget.widgetName].dynamicBindingPathList;
const tableHasData = dataTree[selectedWidget.widgetName].tableData;
const hasBinding =
dynamicBindingPathList &&
!!dynamicBindingPathList.length &&
dynamicBindingPathList.some(
(item: { key: string }) => item.key === "tableData",
);
const errors = get(
selectedWidget,
`${EVAL_ERROR_PATH}.tableData`,
[],
).filter(
(error: EvaluationError) =>
error.errorType !== PropertyEvaluationErrorType.LINT,
);
bindSuccessful =
bindSuccessful &&
hasBinding &&
Array.isArray(tableHasData) &&
tableHasData.length &&
errors.length === 0;
if (bindSuccessful) {
AnalyticsUtil.logEvent("ONBOARDING_SUCCESSFUL_BINDING");
yield put(setCurrentStep(OnboardingStep.ADD_INPUT_WIDGET));
yield delay(1000);
yield put(
setHelperConfig(getHelperConfig(OnboardingStep.ADD_INPUT_WIDGET)),
);
return;
}
}
}
}
}
function* createOnboardingDatasource() {
AnalyticsUtil.logEvent("ONBOARDING_INTRODUCTION");
try {
const isEditorInitialized = yield select(getIsEditorInitialized);
if (!isEditorInitialized)
yield take(ReduxActionTypes.INITIALIZE_EDITOR_SUCCESS);
const organizationId = yield select(getCurrentOrgId);
const plugins = yield select(getPlugins);
const postgresPlugin = plugins.find(
(plugin: Plugin) => plugin.name === "PostgreSQL",
);
const datasources: Datasource[] = yield select(getDatasources);
let onboardingDatasource = datasources.find((datasource) => {
const name = get(datasource, "name");
return name === "Super Updates DB";
});
if (!onboardingDatasource) {
const datasourceConfig: any = {
pluginId: postgresPlugin.id,
name: "Super Updates DB",
organizationId,
datasourceConfiguration: {
connection: {
mode: "READ_WRITE",
ssl: { authType: "DEFAULT" },
},
endpoints: [
{
host: "fake-api.cvuydmurdlas.us-east-1.rds.amazonaws.com",
port: 5432,
},
],
authentication: {
databaseName: "fakeapi",
username: "fakeapi",
password: "LimitedAccess123#",
},
sshProxyEnabled: false,
},
};
const datasourceResponse: GenericApiResponse<Datasource> = yield DatasourcesApi.createDatasource(
datasourceConfig,
);
yield validateResponse(datasourceResponse);
yield checkAndGetPluginFormConfigsSaga(postgresPlugin.id);
yield put({
type: ReduxActionTypes.CREATE_DATASOURCE_SUCCESS,
payload: datasourceResponse.data,
});
onboardingDatasource = datasourceResponse.data;
}
yield put(expandDatasourceEntity(onboardingDatasource.id));
yield put({
type: ReduxActionTypes.CREATE_ONBOARDING_DBQUERY_SUCCESS,
});
// Navigate to that datasource page
yield put(changeDatasource(onboardingDatasource));
yield take(ReduxActionTypes.SHOW_ONBOARDING_LOADER);
yield put(
setHelperConfig(getHelperConfig(OnboardingStep.EXAMPLE_DATABASE)),
);
yield put(showOnboardingHelper(true));
} catch (error) {
yield put({
type: ReduxActionErrorTypes.CREATE_ONBOARDING_DBQUERY_ERROR,
payload: { error },
});
}
}
function* listenForCreateAction() {
const helperConfig = getHelperConfig(OnboardingStep.EXAMPLE_DATABASE);
yield put(showIndicator(OnboardingStep.EXAMPLE_DATABASE));
yield take([ReduxActionTypes.CREATE_ACTION_SUCCESS]);
AnalyticsUtil.logEvent("ONBOARDING_ADD_QUERY");
yield put(
setHelperConfig({
...helperConfig,
image: {
src: "https://assets.appsmith.com/Run.gif",
},
}),
);
yield put(setCurrentSubstep(2));
yield take([
ReduxActionTypes.UPDATE_ACTION_INIT,
ReduxActionTypes.QUERY_PANE_CHANGE,
ReduxActionTypes.RUN_ACTION_REQUEST,
]);
yield take([ReduxActionTypes.RUN_ACTION_SUCCESS]);
AnalyticsUtil.logEvent("ONBOARDING_RUN_QUERY");
yield put(setHelperConfig(getHelperConfig(OnboardingStep.RUN_QUERY_SUCCESS)));
yield put(showIndicator(OnboardingStep.RUN_QUERY_SUCCESS));
yield put(setCurrentStep(OnboardingStep.RUN_QUERY_SUCCESS));
}
function* listenForDeploySaga() {
while (true) {
yield take();
yield put(showIndicator(OnboardingStep.DEPLOY));
yield take(ReduxActionTypes.PUBLISH_APPLICATION_SUCCESS);
AnalyticsUtil.logEvent("ONBOARDING_DEPLOY");
yield call(setOnboardingWelcomeState, false);
yield put(setCurrentStep(OnboardingStep.FINISH));
yield put(setOnboardingReduxState(false));
return;
}
}
function* initiateOnboarding() {
const currentOnboardingState = yield getOnboardingState();
if (currentOnboardingState) {
yield put(setOnboardingReduxState(true));
yield put(setCurrentStep(OnboardingStep.WELCOME));
yield put(setCurrentStep(OnboardingStep.EXAMPLE_DATABASE));
}
}
function* proceedOnboardingSaga() {
const isInOnboarding = yield select(inOnboarding);
if (isInOnboarding) {
yield put({
type: ReduxActionTypes.INCREMENT_STEP,
});
yield setupOnboardingStep();
}
}
function* setupOnboardingStep() {
const currentStep: OnboardingStep = yield select(getCurrentStep);
const currentConfig = OnboardingConfig[currentStep];
let actions = currentConfig.setup();
if (actions.length) {
actions = actions.map((action) => put(action));
yield all(actions);
}
yield delay(500);
playOnboardingStepCompletionAnimation();
}
function* skipOnboardingSaga() {
const set = yield call(setOnboardingState, false);
const resetWelcomeState = yield call(setOnboardingWelcomeState, false);
if (set && resetWelcomeState) {
yield put(setOnboardingReduxState(false));
}
}
function* returnHomeSaga() {
history.push(APPLICATIONS_URL);
yield put(endOnboarding());
AnalyticsUtil.logEvent("ONBOARDING_GO_HOME");
}
function* showEndOnboardingHelperSaga() {
const params = getQueryParams();
const inOnboarding = yield call(getOnboardingState);
if (params.onboardingComplete && inOnboarding) {
yield put(
setHelperConfig(
getHelperConfig(OnboardingStep.FINISH) as OnboardingHelperConfig,
),
);
AnalyticsUtil.logEvent("ONBOARDING_COMPLETE");
yield put(setCurrentSubstep(5));
yield delay(1000);
yield call(playOnboardingAnimation);
yield put(showOnboardingHelper(true));
}
}
// Cheat actions
function* createApplication() {
const colorPalette = yield select(getAppCardColorPalette);
const color = getRandomPaletteColor(colorPalette);
const icon =
AppIconCollection[Math.floor(Math.random() * AppIconCollection.length)];
const currentUser = yield select(getCurrentUser);
const userOrgs: Organization[] = yield select(getOnboardingOrganisations);
const currentOrganizationId = currentUser.currentOrganizationId;
let organization;
const isFirstTimeUserOnboardingdEnabled = yield select(
getIsFirstTimeUserOnboardingEnabled,
);
if (isFirstTimeUserOnboardingdEnabled) {
yield put({
type: ReduxActionTypes.SET_ENABLE_FIRST_TIME_USER_ONBOARDING,
payload: false,
});
yield put({
type: ReduxActionTypes.SET_FIRST_TIME_USER_ONBOARDING_APPLICATION_ID,
payload: "",
});
}
if (!currentOrganizationId) {
organization = userOrgs[0];
} else {
const filteredOrganizations = userOrgs.filter(
(org: any) => org.organization.id === currentOrganizationId,
);
organization = filteredOrganizations[0];
}
// Organization could be undefined for unknown reason
if (organization) {
const applicationList = organization.applications;
const applicationName = getNextEntityName(
"Super Standup ",
applicationList.map((el: any) => el.name),
true,
);
yield put({
type: ReduxActionTypes.CREATE_APPLICATION_INIT,
payload: {
applicationName,
orgId: organization.organization.id,
icon,
color,
},
});
yield take(ReduxActionTypes.CREATE_APPLICATION_SUCCESS);
yield call(initiateOnboarding);
}
}
function* createQuery() {
const currentPageId = yield select(getCurrentPageId);
const applicationId = yield select(getCurrentApplicationId);
const currentSubstep = yield select(getCurrentSubStep);
const datasources: Datasource[] = yield select(getDatasources);
const onboardingDatasource = datasources.find((datasource) => {
const name = get(datasource, "name");
return name === "Super Updates DB";
});
// If the user is on substep 2 of the CREATE_QUERY step
// just run the query.
if (currentSubstep == 2) {
yield put({
type: "ONBOARDING_RUN_QUERY",
});
AnalyticsUtil.logEvent("ONBOARDING_CHEAT", {
step: 1,
});
return;
}
if (onboardingDatasource) {
const payload = {
name: "fetch_standup_updates",
pageId: currentPageId,
pluginId: onboardingDatasource?.pluginId,
datasource: {
id: onboardingDatasource?.id,
},
actionConfiguration: {
body:
"Select avatar, name, notes from standup_updates order by id desc",
timeoutInMillisecond: 30000,
},
} as Partial<QueryAction>;
yield put(createActionRequest(payload));
history.push(
INTEGRATION_EDITOR_URL(
applicationId,
currentPageId,
INTEGRATION_TABS.ACTIVE,
),
);
yield take(ReduxActionTypes.CREATE_ACTION_SUCCESS);
yield put({
type: "ONBOARDING_RUN_QUERY",
});
AnalyticsUtil.logEvent("ONBOARDING_CHEAT", {
step: 1,
});
}
}
function* executeQuery() {
const queryId = getQueryIdFromURL();
if (queryId) {
yield put(runAction(queryId));
}
}
function* addWidget(widgetConfig: any) {
try {
const widget = yield select(getWidgetByName, widgetConfig.widgetName ?? "");
// If widget already exists return
if (widget) return;
const newWidget = {
newWidgetId: generateReactKey(),
widgetId: "0",
parentId: "0",
renderMode: RenderModes.CANVAS,
isLoading: false,
...widgetConfig,
};
yield put({
type: WidgetReduxActionTypes.WIDGET_ADD_CHILD,
payload: newWidget,
});
const pageId = yield select(getCurrentPageId);
const applicationId = yield select(getCurrentApplicationId);
navigateToCanvas({
pageId,
widgetId: newWidget.newWidgetId,
applicationId,
});
yield put({
type: ReduxActionTypes.SELECT_WIDGET_INIT,
payload: { widgetId: newWidget.newWidgetId },
});
} catch (error) {}
}
const getStandupTableDimensions = () => {
const columns = 16 * GRID_DENSITY_MIGRATION_V1;
const rows = 15 * GRID_DENSITY_MIGRATION_V1;
const topRow = 2 * GRID_DENSITY_MIGRATION_V1;
const bottomRow = rows + topRow;
return {
parentRowSpace: 40,
parentColumnSpace: 1,
topRow,
bottomRow,
leftColumn: 0,
rightColumn: columns,
columns: columns,
rows: rows,
};
};
const getStandupInputDimensions = () => {
const columns = 6 * GRID_DENSITY_MIGRATION_V1;
const rows = 1 * GRID_DENSITY_MIGRATION_V1;
const leftColumn = 5 * GRID_DENSITY_MIGRATION_V1;
const rightColumn = leftColumn + columns;
return {
topRow: 1 * GRID_DENSITY_MIGRATION_V1,
bottomRow: 2 * GRID_DENSITY_MIGRATION_V1,
leftColumn,
rightColumn,
rows,
columns,
};
};
const getStandupInputProps = () => ({
placeholderText: "Type your update and hit enter!",
});
function* addTableWidget() {
yield call(addWidget, {
type: WidgetTypes.TABLE_WIDGET,
widgetName: "Standup_Table",
...getStandupTableDimensions(),
props: {
tableData: [],
},
});
AnalyticsUtil.logEvent("ONBOARDING_ADD_WIDGET_CLICK");
AnalyticsUtil.logEvent("ONBOARDING_CHEAT", {
step: 2,
});
}
function* addInputWidget() {
yield call(addWidget, {
type: WidgetTypes.INPUT_WIDGET,
widgetName: "Standup_Input",
...getStandupInputDimensions(),
props: getStandupInputProps(),
});
yield call(addOnSubmitHandler);
}
function* addOnSubmitHandler() {
// Creating a query first
const currentPageId = yield select(getCurrentPageId);
const datasources: Datasource[] = yield select(getDatasources);
const onboardingDatasource = datasources.find((datasource) => {
const name = get(datasource, "name");
return name === "Super Updates DB";
});
if (onboardingDatasource) {
const payload = {
name: "add_standup_updates",
pageId: currentPageId,
pluginId: onboardingDatasource?.pluginId,
datasource: {
id: onboardingDatasource?.id,
},
actionConfiguration: {
body: `Insert into standup_updates("name", "notes") values ('{{appsmith.user.email}}', '{{ Standup_Input.text }}')`,
},
} as Partial<QueryAction>;
yield put(createActionRequest(payload));
yield take(ReduxActionTypes.CREATE_ACTION_SUCCESS);
const widgets = yield select(getWidgets);
const inputWidget: any = Object.values(widgets).find(
(widget: any) => widget.type === "INPUT_WIDGET",
);
if (inputWidget) {
yield delay(1000);
const pageId = yield select(getCurrentPageId);
const applicationId = yield select(getCurrentApplicationId);
navigateToCanvas({
pageId,
widgetId: inputWidget.widgetId,
applicationId,
});
yield put({
type: ReduxActionTypes.SELECT_WIDGET_INIT,
payload: { widgetId: inputWidget.widgetId },
});
yield put(
updateWidgetPropertyRequest(
inputWidget.widgetId,
"onSubmit",
"{{add_standup_updates.run(() => fetch_standup_updates.run(), () => {})}}",
),
);
AnalyticsUtil.logEvent("ONBOARDING_ONSUBMIT_SUCCESS");
yield put(setCurrentStep(OnboardingStep.DEPLOY));
yield put(setHelperConfig(getHelperConfig(OnboardingStep.DEPLOY)));
AnalyticsUtil.logEvent("ONBOARDING_CHEAT", {
step: 4,
});
}
}
}
function* getStandupTableWidget() {
const canvasWidgets: Record<string, any> = yield select(getCanvasWidgets);
const result =
Object.entries(canvasWidgets).find((widgetEntry) => {
const [, widget] = widgetEntry;
return widget.widgetName === "Standup_Table";
}) || [];
const standupTable = result[1];
return standupTable;
}
function* addBinding() {
const standupTable = yield call(getStandupTableWidget);
if (standupTable) {
yield put(
updateWidgetPropertyRequest(
standupTable.widgetId,
"tableData",
"{{fetch_standup_updates.data}}",
),
);
AnalyticsUtil.logEvent("ONBOARDING_CHEAT", {
step: 3,
});
}
}
function* deploy() {
const applicationId = yield select(getCurrentApplicationId);
yield put({
type: ReduxActionTypes.PUBLISH_APPLICATION_INIT,
payload: {
applicationId,
},
});
AnalyticsUtil.logEvent("ONBOARDING_CHEAT", {
step: 5,
});
}
export default function* onboardingSagas() {
while (true) {
const task = yield fork(onboardingActionSagas);
yield take(ReduxActionTypes.END_ONBOARDING);
yield cancel(task);
yield call(skipOnboardingSaga);
}
}
function* setEnableFirstTimeUserOnboarding(action: ReduxAction<boolean>) {
yield storeEnableFirstTimeUserOnboarding(action.payload);
}
function* setFirstTimeUserOnboardingApplicationId(action: ReduxAction<string>) {
yield storeFirstTimeUserOnboardingApplicationId(action.payload);
}
function* setFirstTimeUserOnboardingIntroModalVisibility(
action: ReduxAction<boolean>,
) {
yield storeFirstTimeUserOnboardingIntroModalVisibility(action.payload);
}
function* endFirstTimeUserOnboardingSaga() {
const firstTimeUserExperienceAppId = yield select(
getFirstTimeUserOnboardingApplicationId,
);
yield put({
type: ReduxActionTypes.SET_ENABLE_FIRST_TIME_USER_ONBOARDING,
payload: false,
});
yield put({
type: ReduxActionTypes.SET_FIRST_TIME_USER_ONBOARDING_APPLICATION_ID,
payload: "",
});
Toaster.show({
text: "Skipped First time user experience",
hideProgressBar: false,
variant: Variant.success,
dispatchableAction: {
type: ReduxActionTypes.UNDO_END_FIRST_TIME_USER_ONBOARDING,
payload: firstTimeUserExperienceAppId,
},
});
}
function* undoEndFirstTimeUserOnboardingSaga(action: ReduxAction<string>) {
yield put({
type: ReduxActionTypes.SET_ENABLE_FIRST_TIME_USER_ONBOARDING,
payload: true,
});
yield put({
type: ReduxActionTypes.SET_FIRST_TIME_USER_ONBOARDING_APPLICATION_ID,
payload: action.payload,
});
}
function* firstTimeUserOnboardingInitSaga(
action: ReduxAction<{ applicationId: string; pageId: string }>,
) {
yield put({
type: ReduxActionTypes.SET_ENABLE_FIRST_TIME_USER_ONBOARDING,
payload: true,
});
yield put({
type: ReduxActionTypes.SET_FIRST_TIME_USER_ONBOARDING_APPLICATION_ID,
payload: action.payload.applicationId,
});
yield put({
type: ReduxActionTypes.SET_SHOW_FIRST_TIME_USER_ONBOARDING_MODAL,
payload: true,
});
history.replace(
BUILDER_PAGE_URL({
applicationId: action.payload.applicationId,
pageId: action.payload.pageId,
}),
);
}
function* onboardingActionSagas() {
yield all([
takeLatest(
ReduxActionTypes.CREATE_ONBOARDING_DBQUERY_INIT,
createOnboardingDatasource,
),
takeLatest(ReduxActionTypes.NEXT_ONBOARDING_STEP, proceedOnboardingSaga),
takeLatest(
ReduxActionTypes.LISTEN_FOR_CREATE_ACTION,
listenForCreateAction,
),
takeLatest(
ReduxActionTypes.LISTEN_FOR_ADD_WIDGET,
listenForWidgetAdditions,
),
takeLatest(
ReduxActionTypes.LISTEN_ADD_INPUT_WIDGET,
listenForAddInputWidget,
),
takeLatest(
ReduxActionTypes.LISTEN_FOR_TABLE_WIDGET_BINDING,
listenForSuccessfulBinding,
),
takeLatest(ReduxActionTypes.SET_CURRENT_STEP, setupOnboardingStep),
takeLatest(ReduxActionTypes.LISTEN_FOR_DEPLOY, listenForDeploySaga),
takeLatest(ReduxActionTypes.ONBOARDING_RETURN_HOME, returnHomeSaga),
takeLatest(
ReduxActionTypes.SHOW_END_ONBOARDING_HELPER,
showEndOnboardingHelperSaga,
),
// Cheat actions
takeLatest(ReduxActionTypes.ONBOARDING_CREATE_QUERY, createQuery),
takeLatest(ReduxActionTypes.ONBOARDING_RUN_QUERY, executeQuery),
takeLatest(ReduxActionTypes.ONBOARDING_ADD_TABLE_WIDGET, addTableWidget),
takeLatest(ReduxActionTypes.ONBOARDING_ADD_INPUT_WIDGET, addInputWidget),
takeLatest(
ReduxActionTypes.ONBOARDING_ADD_ONSUBMIT_BINDING,
addOnSubmitHandler,
),
takeLatest(ReduxActionTypes.ONBOARDING_ADD_TABLEDATA_BINDING, addBinding),
takeLatest(ReduxActionTypes.ONBOARDING_DEPLOY, deploy),
takeLatest(
ReduxActionTypes.ONBOARDING_CREATE_APPLICATION,
createApplication,
),
takeLatest(
ReduxActionTypes.SET_ENABLE_FIRST_TIME_USER_ONBOARDING,
setEnableFirstTimeUserOnboarding,
),
takeLatest(
ReduxActionTypes.SET_FIRST_TIME_USER_ONBOARDING_APPLICATION_ID,
setFirstTimeUserOnboardingApplicationId,
),
takeLatest(
ReduxActionTypes.SET_SHOW_FIRST_TIME_USER_ONBOARDING_MODAL,
setFirstTimeUserOnboardingIntroModalVisibility,
),
takeLatest(
ReduxActionTypes.END_FIRST_TIME_USER_ONBOARDING,
endFirstTimeUserOnboardingSaga,
),
takeLatest(
ReduxActionTypes.UNDO_END_FIRST_TIME_USER_ONBOARDING,
undoEndFirstTimeUserOnboardingSaga,
),
takeLatest(
ReduxActionTypes.FIRST_TIME_USER_ONBOARDING_INIT,
firstTimeUserOnboardingInitSaga,
),
]);
}