* temp commit
* using onsubmit to continue using action on form
* added recaptcha site key to env example file
* moved the recaptcha lib loading logic to signup page
* removed unnecessary edit
* handle the case where the recaptcha token is not provided as env var
* added proper env var config for client
* recaptcha config for ansible
* recaptcha config for heroku
* recaptcha config for k8s
* updated app.json
* fixed the typos
* added more description for env vars
* removed api key
* minor typo fix
* added new integration button
* updated the add int default link
* added active and create new tabs
* added the empty components to tabs. will control the section manually.
* added proper grid for integrations page
* added vertical tabs
* Added secondary tabs to integrations page
* added separate page for new apis
* classname changes
* added new components for active queries, new queries etc.
* added a separate component for data source list
* adding screen component conditionally, to be showing upon user's choice
* 1. Added grid styling to datasource home
2. Added connect buttons to em
* fixed data source security banner
* updated the styling for new api page
* added tertiary menu for active integrations
* updated styling for active connections
* updated collapse component to work properly
* added show more option to active data sources
* Slash commands feature init commit
* Added more commands
* Introduced JSX to render custom commands
* Merge conflict fix
* Spacing changes
* removed apis/db tabs and replaced em with integrations tab
* removed the unnecessary + integrations btn
* Added slash commands button
* Adjust styles for better ui
* Ordered the action entries under integrations
* Added new datasource command
* updated the getURL with proper params
* updated the link of create datasource btn
* updated the back btn link from data source editor
* Show connect data cta in property pane
* Styling fixes
* Fix margin
* added scrollable content to create new
* added on click scroll to create new page
* fixed a bug, creating new datasource twice
* added new action creator for integrations.
* Minor changes to add new bindings command.
Changed ui behaviour of / button
* UI style change
* updated the query editor to match the over all theme
* updated the query editor tabs
* Added the run btn to empty response screens
* minor fix
* updated the bg color of api type drop down
* updated the url being visited after delete api/query
* removed log
* Insert binding command UI change
* More UI changes
* removed unnecessary junk from integrations editor index
* clean up, removed unnecessary files
* removed useless routes
* for debugger only checking if integrations editor
* Removed all the links for api/query home pages
* Move command actions to a saga
Added support to binding the data back to the widget when are new API is created from widget
* Added reverse binding for DB queries
* Show / button only on hover
* not routing to integrations on create query/api
* Hide actions from suggestions in action pages
* removed the query/datasource/api home pages
* Changes widget.data to widget in slash commands
* Show dependencies in property pane
* Fix warning
* fixed scrolling issue
* will show a list of queries and apis for action picker
* showing icons for each action under integrations
* Fix dropdown not showing up
* Minor refactoring.
Changed commands
* added a way to list data sources in action creators
* Update query page url
* cam show icons for datasources
* Removed unused code
* Feature/slash commands (#5002)
* Slash commands feature init commit
* Added more commands
* Introduced JSX to render custom commands
* Merge conflict fix
* Spacing changes
* Added slash commands button
* Adjust styles for better ui
* Added new datasource command
* Minor changes to add new bindings command.
Changed ui behaviour of / button
* UI style change
* Insert binding command UI change
* More UI changes
* Move command actions to a saga
Added support to binding the data back to the widget when are new API is created from widget
* Added reverse binding for DB queries
* Show / button only on hover
* Hide actions from suggestions in action pages
* Changes widget.data to widget in slash commands
* Minor refactoring.
Changed commands
* Removed unused code
* remove more unusued code
* Added support to generate new api from a datasource in quick commands
* Code correction to use types
* Refactored commands code
* Minor bug fixes
* Remove new integrations command for actions.
Fixed autocomplete not showing up
* Changes to prevent autocomplete trigger for navigation commands
* Prevent hinter execution when show hint is open already.
* Show hinter on focus
* Update text to be called in the omnibar
* updated the copy for empty active datasources
* Update url
* Fix text decoration
* updated the redirection for back btns
* Use themes
* Add cypress test
* fixed back btn nav
* fetching form configs for datasources
* a callback fixed
* Fix slash command not executed on click (#5540)
* Replace the value if not a string else append
* Log commands menu events
* updated mock data base navigation
* updated mock data base navigation
* updated the close editors and back buttons
* All back btns from editors will go back to data sources and back from data source will go back to canvas
* fixed bg colors
* minor styled updates
* removed margin from header of generic datasource
* warnings fixes
* If user is already on the location not redirecting em
* when editing, will check if the coming from data source and redirect accordingly
* updated redirection for newly created api/queries
* updated back btn for newly created datasources
* back for new curl goes to data sources
* Revert "[Fix] revert new nav (#5533)"
This reverts commit 1647815d
* remaining original reverted chagnes
* fixed the width of incoming/outgoing entity bar in property pane
* removing residue from resolved merge conflicts
* Fix widget icons not visible in dropdown menu
* minor fix to use proper integration URL
* updated the URLs for unified datasources
* converted back and close to btns from banners
* on accessing data source from sidebar, it'll always go to view mode
* updated the edit path for saas editors
* Added saved state for google sheet
* on google sheet delete redirecting to create new
* minor fix
* fixed the redirection call on saving a datasource
* removed save and test cmd as it wasn't needed
* Removing test cases to be fixed by Arun
* commenting more tests to be fixed by Arun
* updated call api cy command
* Fix extra margin issue
* fixed the update datasource saga
* fixed video spec
* Revert "commenting more tests to be fixed by Arun"
This reverts commit 42087a95ad77107401a1619e4c2d4c541a81d6c3.
* Revert "Removing test cases to be fixed by Arun"
This reverts commit f6fad67e558d22045114a90409428ef9b737478f.
* fixed the entity explorer query datasource spec
* cautious fix
* update widget locators
* fixed leave org test
* fixes for FormWidgets
* updated the image spec
* Use memo
* Fix debugger url checks
* for copy and delete widget pointing directly to svgs
* Fix entity text
* Fix styling and show tooltip for property pane dependencies
* removed the unnecessary callback
* added a separate saga to to redirect to new integrations using onSuccess
* Bug Fixes - New nav (#5629)
* will show scrollbar only on hover
* made mock data cards clickable
* fixed the grid view
* fixed the cursor position when clicking on / btn
* updated the hint for `/` command
* binding prompt will close on focus change
* hiding / command for api body
* hiding / command for query pane
* Added 2 new icons
* Fix cursor position on selecting a binding and clicking on the slash menu button
* trying out fix to copyWidget cy command
* removing zero width space characters from the property pane text
Co-authored-by: arunvjn <arun@appsmith.com>
Co-authored-by: Akash N <akash@codemonk.in>
Co-authored-by: arunvjn <32433245+arunvjn@users.noreply.github.com>
Co-authored-by: Rishabh Saxena <rishabh.robben@gmail.com>
936 lines
26 KiB
TypeScript
936 lines
26 KiB
TypeScript
import { GenericApiResponse } from "api/ApiResponses";
|
|
import DatasourcesApi from "api/DatasourcesApi";
|
|
import { Datasource } from "entities/Datasource";
|
|
import { Plugin } from "api/PluginApi";
|
|
import {
|
|
ReduxActionErrorTypes,
|
|
ReduxActionTypes,
|
|
} 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,
|
|
setOnboardingState,
|
|
setOnboardingWelcomeState,
|
|
} from "utils/storage";
|
|
import { validateResponse } from "./ErrorSagas";
|
|
import { getSelectedWidget, 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,
|
|
} 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 { getUserApplicationsOrgs } from "selectors/applicationSelectors";
|
|
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, runActionInit } from "actions/actionActions";
|
|
import {
|
|
APPLICATIONS_URL,
|
|
BUILDER_PAGE_URL,
|
|
INTEGRATION_EDITOR_URL,
|
|
INTEGRATION_TABS,
|
|
} 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, WidgetTypes } from "constants/WidgetConstants";
|
|
import { generateReactKey } from "utils/generators";
|
|
import { forceOpenPropertyPane } from "actions/widgetActions";
|
|
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 { GRID_DENSITY_MIGRATION_V1 } from "mockResponses/WidgetConfigResponse";
|
|
import {
|
|
EVAL_ERROR_PATH,
|
|
EvaluationError,
|
|
PropertyEvaluationErrorType,
|
|
} from "utils/DynamicBindingUtils";
|
|
|
|
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: 20,
|
|
name: 30,
|
|
},
|
|
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",
|
|
);
|
|
|
|
if (
|
|
inputWidget &&
|
|
inputWidget.type === "INPUT_WIDGET" &&
|
|
canvasWidgets[inputWidget.widgetId]
|
|
) {
|
|
if (
|
|
!window.location.pathname.includes(
|
|
BUILDER_PAGE_URL(applicationId, currentPageId),
|
|
)
|
|
) {
|
|
yield cancel();
|
|
}
|
|
|
|
AnalyticsUtil.logEvent("ONBOARDING_ADD_WIDGET_INPUT");
|
|
|
|
if (inputWidget.widgetName !== "Standup_Input") {
|
|
yield put(
|
|
updateWidgetPropertyRequest(
|
|
inputWidget.widgetId,
|
|
"widgetName",
|
|
"Standup_Input",
|
|
RenderModes.CANVAS,
|
|
),
|
|
);
|
|
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(), () => {})}}",
|
|
RenderModes.CANVAS,
|
|
),
|
|
);
|
|
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) {
|
|
yield put(
|
|
batchUpdateWidgetProperty(selectedWidget.widgetId, {
|
|
modify: {
|
|
columnTypeMap: {
|
|
avatar: {
|
|
type: "image",
|
|
format: "",
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
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://res.cloudinary.com/drako999/image/upload/v1611839705/Appsmith/Onboarding/run.gif",
|
|
},
|
|
}),
|
|
);
|
|
yield put(setCurrentSubstep(2));
|
|
|
|
yield take([
|
|
ReduxActionTypes.UPDATE_ACTION_INIT,
|
|
ReduxActionTypes.QUERY_PANE_CHANGE,
|
|
ReduxActionTypes.RUN_ACTION_INIT,
|
|
]);
|
|
|
|
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 = yield select(getUserApplicationsOrgs);
|
|
const currentOrganizationId = currentUser.currentOrganizationId;
|
|
let organization;
|
|
|
|
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(runActionInit(queryId));
|
|
}
|
|
}
|
|
|
|
function* addWidget(widgetConfig: any) {
|
|
try {
|
|
const newWidget = {
|
|
newWidgetId: generateReactKey(),
|
|
widgetId: "0",
|
|
parentId: "0",
|
|
renderMode: RenderModes.CANVAS,
|
|
isLoading: false,
|
|
...widgetConfig,
|
|
};
|
|
|
|
yield put({
|
|
type: ReduxActionTypes.WIDGET_ADD_CHILD,
|
|
payload: newWidget,
|
|
});
|
|
|
|
const applicationId = yield select(getCurrentApplicationId);
|
|
const pageId = yield select(getCurrentPageId);
|
|
|
|
navigateToCanvas(
|
|
{
|
|
applicationId,
|
|
pageId,
|
|
},
|
|
window.location.pathname,
|
|
pageId,
|
|
newWidget.newWidgetId,
|
|
);
|
|
yield put({
|
|
type: ReduxActionTypes.SELECT_WIDGET_INIT,
|
|
payload: { widgetId: newWidget.newWidgetId },
|
|
});
|
|
yield put(forceOpenPropertyPane(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 applicationId = yield select(getCurrentApplicationId);
|
|
const pageId = yield select(getCurrentPageId);
|
|
|
|
navigateToCanvas(
|
|
{
|
|
applicationId,
|
|
pageId,
|
|
},
|
|
window.location.pathname,
|
|
pageId,
|
|
inputWidget.widgetId,
|
|
);
|
|
yield put({
|
|
type: ReduxActionTypes.SELECT_WIDGET_INIT,
|
|
payload: { widgetId: inputWidget.widgetId },
|
|
});
|
|
yield put(forceOpenPropertyPane(inputWidget.widgetId));
|
|
|
|
yield put(
|
|
updateWidgetPropertyRequest(
|
|
inputWidget.widgetId,
|
|
"onSubmit",
|
|
"{{add_standup_updates.run(() => fetch_standup_updates.run(), () => {})}}",
|
|
RenderModes.CANVAS,
|
|
),
|
|
);
|
|
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}}",
|
|
RenderModes.CANVAS,
|
|
),
|
|
);
|
|
|
|
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* 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,
|
|
),
|
|
]);
|
|
}
|