chore: Update integration modal (#39976)
/ok-to-test tags="@tag.Datasource" <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Action creators now support optional callbacks and redirection controls to enhance query operations. - UI tabs can now be configured to remain persistently mounted, ensuring a smoother editing experience. - New functionality to add datasources to the existing list without complex tracking. - **Bug Fixes** - Simplified logic for determining the saving state of datasources, improving UI responsiveness. - **Refactor** - Datasource creation and saving state handling have been streamlined for improved reliability. - Enhanced management of action payloads and state updates enables more robust processing of user operations. - Improved type safety and clarity in action handling within sagas for better maintainability. <!-- end of auto-generated comment: release notes by coderabbit.ai --> <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/14167301395> > Commit: be05d6bda56aff96421faf435804f56707a597ba > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=14167301395&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Datasource` > Spec: > <hr>Mon, 31 Mar 2025 09:14:22 UTC <!-- end of auto-generated comment: Cypress test results -->
This commit is contained in:
parent
a25f5f9f15
commit
ae80556758
|
|
@ -396,6 +396,17 @@ export const setUnconfiguredDatasourcesDuringImport = (
|
|||
payload,
|
||||
});
|
||||
|
||||
// this actions concats the newly created datasource to the datasource list
|
||||
// it's not required if createDatasourceSuccess is used, that also concats the new datasource to the datasource list
|
||||
// The main difference between this and createDatasourceSuccess is that this action only adds the datasource to the datasource list
|
||||
// and is not tracked by any saga, whereas createDatasourceSuccess is tracked by many sagas with different logic.
|
||||
export const updateDatasoruceRefs = (datasource: Datasource) => {
|
||||
return {
|
||||
type: ReduxActionTypes.UPDATE_DATASOURCE_REFS,
|
||||
payload: datasource,
|
||||
};
|
||||
};
|
||||
|
||||
export const removeTempDatasource = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.REMOVE_TEMP_DATASOURCE_SUCCESS,
|
||||
|
|
|
|||
|
|
@ -21,20 +21,30 @@ import type { GenerateDestinationIdInfoReturnType } from "ee/sagas/helpers";
|
|||
import type { Span } from "instrumentation/types";
|
||||
import type { EvaluationReduxAction } from "./EvaluationReduxActionTypes";
|
||||
|
||||
export const createActionRequest = (payload: Partial<Action>) => {
|
||||
export const createActionRequest = (
|
||||
payload: Partial<Action>,
|
||||
onSuccess?: ReduxAction<unknown>,
|
||||
) => {
|
||||
return {
|
||||
type: ReduxActionTypes.CREATE_ACTION_REQUEST,
|
||||
payload,
|
||||
onSuccess,
|
||||
};
|
||||
};
|
||||
export const createActionInit = (payload: Partial<Action>) => {
|
||||
export const createActionInit = (
|
||||
payload: Partial<Action>,
|
||||
onSuccess?: ReduxAction<unknown>,
|
||||
) => {
|
||||
return {
|
||||
type: ReduxActionTypes.CREATE_ACTION_INIT,
|
||||
payload,
|
||||
onSuccess,
|
||||
};
|
||||
};
|
||||
|
||||
export const createActionSuccess = (payload: Action) => {
|
||||
export const createActionSuccess = (
|
||||
payload: Action & { shouldRedirectToQueryEditor?: boolean },
|
||||
) => {
|
||||
return {
|
||||
type: ReduxActionTypes.CREATE_ACTION_SUCCESS,
|
||||
payload,
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ import {
|
|||
changeDatasource,
|
||||
createDatasourceSuccess,
|
||||
createTempDatasourceFromForm,
|
||||
deleteTempDSFromDraft,
|
||||
fetchDatasourceStructure,
|
||||
removeTempDatasource,
|
||||
resetDefaultKeyValPairFlag,
|
||||
|
|
@ -184,6 +185,7 @@ import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionH
|
|||
import { getCurrentModuleId } from "ee/selectors/modulesSelector";
|
||||
import type { ApplicationPayload } from "entities/Application";
|
||||
import { openGeneratePageModalWithSelectedDS } from "../../utils/GeneratePageUtils";
|
||||
import { createDatasourceAPIPayloadFromAction } from "ee/sagas/helpers";
|
||||
|
||||
export function* fetchDatasourcesSaga(
|
||||
action: ReduxAction<
|
||||
|
|
@ -1189,9 +1191,8 @@ export function* createDatasourceFromFormSaga(
|
|||
checkAndGetPluginFormConfigsSaga,
|
||||
actionPayload.payload.pluginId,
|
||||
);
|
||||
// TODO: Fix this the next time the file is edited
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const formConfig: Record<string, any>[] = yield select(
|
||||
|
||||
const formConfig: ReturnType<typeof getPluginForm> = yield select(
|
||||
getPluginForm,
|
||||
actionPayload.payload.pluginId,
|
||||
);
|
||||
|
|
@ -1199,35 +1200,16 @@ export function* createDatasourceFromFormSaga(
|
|||
getCurrentEditingEnvironmentId,
|
||||
);
|
||||
|
||||
const initialValues: unknown = yield call(
|
||||
const initialValues: ReturnType<typeof getConfigInitialValues> = yield call(
|
||||
getConfigInitialValues,
|
||||
formConfig,
|
||||
);
|
||||
let datasourceStoragePayload =
|
||||
actionPayload.payload.datasourceStorages[currentEnvironment];
|
||||
|
||||
datasourceStoragePayload = merge(initialValues, datasourceStoragePayload);
|
||||
|
||||
// in the datasourcestorages, we only need one key, the currentEnvironment
|
||||
// we need to remove any other keys present
|
||||
const datasourceStorages = {
|
||||
[currentEnvironment]: datasourceStoragePayload,
|
||||
};
|
||||
|
||||
const payload = omit(
|
||||
{
|
||||
...actionPayload.payload,
|
||||
datasourceStorages,
|
||||
},
|
||||
["id", "new", "type", "datasourceConfiguration"],
|
||||
);
|
||||
|
||||
if (payload.datasourceStorages)
|
||||
datasourceStoragePayload.isConfigured = true;
|
||||
|
||||
// remove datasourceId from payload if it is equal to TEMP_DATASOURCE_ID
|
||||
if (datasourceStoragePayload.datasourceId === TEMP_DATASOURCE_ID)
|
||||
datasourceStoragePayload.datasourceId = "";
|
||||
const payload = createDatasourceAPIPayloadFromAction({
|
||||
actionPayload: actionPayload.payload,
|
||||
currentEnvId: currentEnvironment,
|
||||
initialValues,
|
||||
});
|
||||
|
||||
const response: ApiResponse<Datasource> =
|
||||
yield DatasourcesApi.createDatasource({
|
||||
|
|
@ -1260,14 +1242,11 @@ export function* createDatasourceFromFormSaga(
|
|||
isFormValid: isFormValid,
|
||||
editedFields: formDiffPaths,
|
||||
connectionMethod: getConnectionMethod(
|
||||
datasourceStoragePayload,
|
||||
payload.datasourceStorages?.[currentEnvironment] as DatasourceStorage,
|
||||
plugin?.packageName,
|
||||
),
|
||||
});
|
||||
yield put({
|
||||
type: ReduxActionTypes.UPDATE_DATASOURCE_REFS,
|
||||
payload: response.data,
|
||||
});
|
||||
|
||||
yield put(
|
||||
createDatasourceSuccess(
|
||||
response.data,
|
||||
|
|
@ -1307,12 +1286,7 @@ export function* createDatasourceFromFormSaga(
|
|||
yield put(actionPayload.onSuccess);
|
||||
}
|
||||
|
||||
yield put({
|
||||
type: ReduxActionTypes.DELETE_DATASOURCE_DRAFT,
|
||||
payload: {
|
||||
id: TEMP_DATASOURCE_ID,
|
||||
},
|
||||
});
|
||||
yield put(deleteTempDSFromDraft());
|
||||
|
||||
// for all datasources, except for REST and GraphQL, need to delete temp datasource data
|
||||
// as soon as possible, for REST and GraphQL it is getting deleted in APIPaneSagas.ts
|
||||
|
|
@ -1323,6 +1297,8 @@ export function* createDatasourceFromFormSaga(
|
|||
// updating form initial values to latest data, so that next time when form is opened
|
||||
// isDirty will use updated initial values data to compare actual values with
|
||||
yield put(initialize(DATASOURCE_DB_FORM, response.data));
|
||||
|
||||
return response.data;
|
||||
}
|
||||
} catch (error) {
|
||||
yield put({
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
import omit from "lodash/omit";
|
||||
import merge from "lodash/merge";
|
||||
import type { CreateNewActionKeyInterface } from "ee/entities/Engine/actionHelpers";
|
||||
import { CreateNewActionKey } from "ee/entities/Engine/actionHelpers";
|
||||
import type { DeleteErrorLogPayload } from "actions/debuggerActions";
|
||||
import type { Action } from "entities/Action";
|
||||
import type { Log } from "entities/AppsmithConsole";
|
||||
import type { EvaluationError } from "utils/DynamicBindingUtils";
|
||||
import { TEMP_DATASOURCE_ID } from "constants/Datasource";
|
||||
import type { getConfigInitialValues } from "components/formControls/utils";
|
||||
import type { CreateDatasourceConfig } from "ee/api/DatasourcesApi";
|
||||
import type { Datasource } from "entities/Datasource";
|
||||
|
||||
export interface ResolveParentEntityMetadataReturnType {
|
||||
parentEntityId?: string;
|
||||
|
|
@ -52,3 +58,41 @@ export function* transformDeleteErrorLogsSaga(payload: DeleteErrorLogPayload) {
|
|||
export function* transformTriggerEvalErrors(errors: EvaluationError[]) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
interface CreateDatasourcePayloadFromActionParams {
|
||||
currentEnvId: string;
|
||||
actionPayload: Datasource | CreateDatasourceConfig;
|
||||
initialValues: ReturnType<typeof getConfigInitialValues>;
|
||||
}
|
||||
|
||||
export const createDatasourceAPIPayloadFromAction = (
|
||||
props: CreateDatasourcePayloadFromActionParams,
|
||||
) => {
|
||||
const { actionPayload, currentEnvId, initialValues } = props;
|
||||
|
||||
let datasourceStoragePayload = actionPayload.datasourceStorages[currentEnvId];
|
||||
|
||||
datasourceStoragePayload = merge(initialValues, datasourceStoragePayload);
|
||||
|
||||
// in the datasourcestorages, we only need one key, the currentEnvironment
|
||||
// we need to remove any other keys present
|
||||
const datasourceStorages = {
|
||||
[currentEnvId]: datasourceStoragePayload,
|
||||
};
|
||||
|
||||
const payload = omit(
|
||||
{
|
||||
...actionPayload,
|
||||
datasourceStorages,
|
||||
},
|
||||
["id", "new", "type", "datasourceConfiguration"],
|
||||
);
|
||||
|
||||
if (payload.datasourceStorages) datasourceStoragePayload.isConfigured = true;
|
||||
|
||||
// remove datasourceId from payload if it is equal to TEMP_DATASOURCE_ID
|
||||
if (datasourceStoragePayload.datasourceId === TEMP_DATASOURCE_ID)
|
||||
datasourceStoragePayload.datasourceId = "";
|
||||
|
||||
return payload;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ export interface BottomTab {
|
|||
title: string;
|
||||
count?: number;
|
||||
panelComponent: React.ReactNode;
|
||||
forceMount?: true;
|
||||
}
|
||||
|
||||
interface EntityBottomTabsProps {
|
||||
|
|
@ -93,7 +94,11 @@ function EntityBottomTabs(
|
|||
})}
|
||||
</TabsListWrapper>
|
||||
{props.tabs.map((tab) => (
|
||||
<TabPanelWrapper key={tab.key} value={tab.key}>
|
||||
<TabPanelWrapper
|
||||
forceMount={tab.forceMount}
|
||||
key={tab.key}
|
||||
value={tab.key}
|
||||
>
|
||||
{tab.panelComponent}
|
||||
</TabPanelWrapper>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -1199,7 +1199,7 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
|
|||
formName,
|
||||
isInsideReconnectModal: props.isInsideReconnectModal ?? false,
|
||||
pluginId,
|
||||
isSaving: datasources.loading && datasources.loadingPluginId === pluginId,
|
||||
isSaving: datasources.loading,
|
||||
isDeleting: !!(datasource as Datasource)?.isDeleting,
|
||||
isPluginAuthorized: !!isPluginAuthorized,
|
||||
isTesting: datasources.isTesting,
|
||||
|
|
|
|||
|
|
@ -858,7 +858,7 @@ const mapStateToProps = (state: AppState, props: any) => {
|
|||
datasourceButtonConfiguration,
|
||||
datasourceId,
|
||||
documentationLink: documentationLinks[pluginId],
|
||||
isSaving: datasources.loading && datasources.loadingPluginId === pluginId,
|
||||
isSaving: datasources.loading,
|
||||
isDeleting: !!datasource?.isDeleting,
|
||||
isTesting: datasources.isTesting,
|
||||
formData: formData,
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ import { assign } from "lodash";
|
|||
export interface DatasourceDataState {
|
||||
list: Datasource[];
|
||||
loading: boolean;
|
||||
// this prop tells which plugin is being loaded. Mainly used on the save button of datasource editor page.
|
||||
loadingPluginId: string | null;
|
||||
loadingTokenForDatasourceId: string | null;
|
||||
isTesting: boolean;
|
||||
isListing: boolean; // fetching unconfigured datasource list
|
||||
|
|
@ -51,7 +49,6 @@ export interface DatasourceDataState {
|
|||
const initialState: DatasourceDataState = {
|
||||
list: [],
|
||||
loading: false,
|
||||
loadingPluginId: null,
|
||||
loadingTokenForDatasourceId: null,
|
||||
isTesting: false,
|
||||
isListing: false,
|
||||
|
|
@ -121,14 +118,10 @@ const datasourceReducer = createReducer(initialState, {
|
|||
[ReduxActionTypes.FETCH_DATASOURCES_INIT]: (state: DatasourceDataState) => {
|
||||
return { ...state, loading: true };
|
||||
},
|
||||
[ReduxActionTypes.CREATE_DATASOURCE_INIT]: (
|
||||
state: DatasourceDataState,
|
||||
action: ReduxAction<{ pluginId: string }>,
|
||||
) => {
|
||||
[ReduxActionTypes.CREATE_DATASOURCE_INIT]: (state: DatasourceDataState) => {
|
||||
return {
|
||||
...state,
|
||||
loading: true,
|
||||
loadingPluginId: action.payload.pluginId,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.CREATE_DATASOURCE_FROM_FORM_INIT]: (
|
||||
|
|
@ -143,7 +136,6 @@ const datasourceReducer = createReducer(initialState, {
|
|||
return {
|
||||
...state,
|
||||
loading: !!action.payload.loading,
|
||||
loadingPluginId: null,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.UPDATE_DATASOURCE_INIT]: (state: DatasourceDataState) => {
|
||||
|
|
@ -342,6 +334,15 @@ const datasourceReducer = createReducer(initialState, {
|
|||
}),
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.UPDATE_DATASOURCE_REFS]: (
|
||||
state: DatasourceDataState,
|
||||
action: ReduxAction<Datasource>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
list: state.list.concat(action.payload),
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.CREATE_DATASOURCE_SUCCESS]: (
|
||||
state: DatasourceDataState,
|
||||
action: ReduxAction<Datasource>,
|
||||
|
|
|
|||
|
|
@ -51,7 +51,10 @@ import {
|
|||
ERROR_ACTION_MOVE_FAIL,
|
||||
ERROR_ACTION_RENAME_FAIL,
|
||||
} from "ee/constants/messages";
|
||||
import type { ReduxAction } from "actions/ReduxActionTypes";
|
||||
import type {
|
||||
ReduxAction,
|
||||
ReduxActionWithCallbacks,
|
||||
} from "actions/ReduxActionTypes";
|
||||
import {
|
||||
ReduxActionErrorTypes,
|
||||
ReduxActionTypes,
|
||||
|
|
@ -271,24 +274,31 @@ export function* getPluginActionDefaultValues(pluginId: string) {
|
|||
return initialValues;
|
||||
}
|
||||
|
||||
type CreateActionRequestSagaAction = Partial<Action> & {
|
||||
eventData?: unknown;
|
||||
pluginId: string;
|
||||
shouldRedirectToQueryEditor?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* This saga prepares the action request i.e it helps generating a
|
||||
* new name of an action. This is to reduce any dependency on name generation
|
||||
* on the caller of this saga.
|
||||
*/
|
||||
export function* createActionRequestSaga(
|
||||
actionPayload: ReduxAction<
|
||||
Partial<Action> & { eventData?: unknown; pluginId: string }
|
||||
action: ReduxActionWithCallbacks<
|
||||
CreateActionRequestSagaAction,
|
||||
unknown,
|
||||
unknown
|
||||
>,
|
||||
) {
|
||||
const payload = { ...actionPayload.payload };
|
||||
const payload = { ...action.payload };
|
||||
const pluginId =
|
||||
actionPayload.payload.pluginId ||
|
||||
actionPayload.payload.datasource?.pluginId;
|
||||
action.payload.pluginId || action.payload.datasource?.pluginId;
|
||||
|
||||
if (!actionPayload.payload.name) {
|
||||
if (!action.payload.name) {
|
||||
const { parentEntityId, parentEntityKey } = resolveParentEntityMetadata(
|
||||
actionPayload.payload,
|
||||
action.payload,
|
||||
);
|
||||
|
||||
if (!parentEntityId || !parentEntityKey) return;
|
||||
|
|
@ -314,20 +324,22 @@ export function* createActionRequestSaga(
|
|||
});
|
||||
}
|
||||
|
||||
yield put(createActionInit(payload));
|
||||
yield put(createActionInit(payload, action.onSuccess));
|
||||
}
|
||||
|
||||
type CreateActionSagaPayload = Partial<Action> & {
|
||||
eventData: unknown;
|
||||
pluginId: string;
|
||||
shouldRedirectToQueryEditor?: boolean;
|
||||
};
|
||||
|
||||
export function* createActionSaga(
|
||||
actionPayload: ReduxAction<
|
||||
// TODO: Fix this the next time the file is edited
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
Partial<Action> & { eventData: any; pluginId: string }
|
||||
>,
|
||||
action: ReduxActionWithCallbacks<CreateActionSagaPayload, unknown, unknown>,
|
||||
) {
|
||||
try {
|
||||
// Indicates that source of action creation is self
|
||||
actionPayload.payload.source = ActionCreationSourceTypeEnum.SELF;
|
||||
const payload = actionPayload.payload;
|
||||
action.payload.source = ActionCreationSourceTypeEnum.SELF;
|
||||
const payload = action.payload;
|
||||
|
||||
const response: ApiResponse<ActionCreateUpdateResponse> =
|
||||
yield ActionAPI.createAction(payload);
|
||||
|
|
@ -344,7 +356,7 @@ export function* createActionSaga(
|
|||
// @ts-expect-error: name does not exists on type ActionCreateUpdateResponse
|
||||
actionName: response.data.name,
|
||||
pageName: pageName,
|
||||
...actionPayload.payload.eventData,
|
||||
...action.payload.eventData,
|
||||
});
|
||||
|
||||
AppsmithConsole.info({
|
||||
|
|
@ -360,8 +372,17 @@ export function* createActionSaga(
|
|||
|
||||
const newAction = response.data;
|
||||
|
||||
// @ts-expect-error: type mismatch ActionCreateUpdateResponse vs Action
|
||||
yield put(createActionSuccess(newAction));
|
||||
yield put(
|
||||
createActionSuccess({
|
||||
...(newAction as unknown as Action),
|
||||
shouldRedirectToQueryEditor:
|
||||
action.payload.shouldRedirectToQueryEditor,
|
||||
}),
|
||||
);
|
||||
|
||||
if (action.onSuccess) {
|
||||
yield put(action.onSuccess);
|
||||
}
|
||||
|
||||
// we fork to prevent the call from blocking
|
||||
yield fork(fetchActionDatasourceStructure, newAction);
|
||||
|
|
@ -369,7 +390,7 @@ export function* createActionSaga(
|
|||
} catch (error) {
|
||||
yield put({
|
||||
type: ReduxActionErrorTypes.CREATE_ACTION_ERROR,
|
||||
payload: actionPayload.payload,
|
||||
payload: action.payload,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -392,14 +392,17 @@ function* formValueChangeSaga(
|
|||
}
|
||||
}
|
||||
|
||||
function* handleQueryCreatedSaga(actionPayload: ReduxAction<QueryAction>) {
|
||||
function* handleQueryCreatedSaga(
|
||||
action: ReduxAction<QueryAction & { shouldRedirectToQueryEditor?: boolean }>,
|
||||
) {
|
||||
const {
|
||||
actionConfiguration,
|
||||
baseId: baseActionId,
|
||||
pageId,
|
||||
pluginId,
|
||||
pluginType,
|
||||
} = actionPayload.payload;
|
||||
shouldRedirectToQueryEditor = true,
|
||||
} = action.payload;
|
||||
|
||||
if (
|
||||
![
|
||||
|
|
@ -424,17 +427,19 @@ function* handleQueryCreatedSaga(actionPayload: ReduxAction<QueryAction>) {
|
|||
|
||||
const basePageId: string = yield select(convertToBasePageIdSelector, pageId);
|
||||
|
||||
history.replace(
|
||||
queryEditorIdURL({
|
||||
basePageId,
|
||||
baseQueryId: baseActionId,
|
||||
params: {
|
||||
editName: "true",
|
||||
showTemplate,
|
||||
from: "datasources",
|
||||
},
|
||||
}),
|
||||
);
|
||||
if (shouldRedirectToQueryEditor) {
|
||||
history.replace(
|
||||
queryEditorIdURL({
|
||||
basePageId,
|
||||
baseQueryId: baseActionId,
|
||||
params: {
|
||||
editName: "true",
|
||||
showTemplate,
|
||||
from: "datasources",
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function* handleDatasourceCreatedSaga(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import type { ActionData } from "ee/reducers/entityReducers/actionsReducer";
|
|||
import type { Page } from "entities/Page";
|
||||
import { getActions, getPlugins } from "ee/selectors/entitiesSelector";
|
||||
import type { Plugin } from "entities/Plugin";
|
||||
import type { DragDetails } from "reducers/uiReducers/dragResizeReducer";
|
||||
import type { DataTreeForActionCreator } from "components/editorComponents/ActionCreator/types";
|
||||
import type { MetaWidgetsReduxState } from "reducers/entityReducers/metaWidgetsReducer";
|
||||
|
||||
|
|
@ -248,7 +247,7 @@ export const getIsNewWidgetBeingDragged = (state: AppState) => {
|
|||
|
||||
if (!isDragging) return false;
|
||||
|
||||
const dragDetails: DragDetails = getDragDetails(state);
|
||||
const dragDetails = getDragDetails(state);
|
||||
const { dragGroupActualParent: dragParent, newWidget } = dragDetails;
|
||||
|
||||
return !!newWidget && !dragParent;
|
||||
|
|
@ -258,7 +257,7 @@ export const isCurrentCanvasDragging = createSelector(
|
|||
(state: AppState) => state.ui.widgetDragResize.isDragging,
|
||||
getDragDetails,
|
||||
(state: AppState, canvasId: string) => canvasId,
|
||||
(isDragging: boolean, dragDetails: DragDetails, canvasId: string) => {
|
||||
(isDragging: boolean, dragDetails, canvasId: string) => {
|
||||
return dragDetails?.draggedOn === canvasId && isDragging;
|
||||
},
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user