in superset-frontend/src/dashboard/actions/dashboardLayout.js [172:268]
export function handleComponentDrop(dropResult) {
return (dispatch, getState) => {
const overflowsParent = dropOverflowsParent(
dropResult,
getState().dashboardLayout.present,
);
if (overflowsParent) {
return dispatch(
addWarningToast(
t(
`There is not enough space for this component. Try decreasing its width, or increasing the destination width.`,
),
),
);
}
const { source, destination } = dropResult;
const droppedOnRoot = destination && destination.id === DASHBOARD_ROOT_ID;
const isNewComponent = source.id === NEW_COMPONENTS_SOURCE_ID;
const dashboardRoot = getState().dashboardLayout.present[DASHBOARD_ROOT_ID];
const rootChildId =
dashboardRoot && dashboardRoot.children ? dashboardRoot.children[0] : '';
if (droppedOnRoot) {
dispatch(createTopLevelTabs(dropResult));
} else if (destination && isNewComponent) {
dispatch(createComponent(dropResult));
} else if (
// Add additional allow-to-drop logic for tag/tags source.
// We only allow
// - top-level tab => top-level tab: rearrange top-level tab order
// - nested tab => top-level tab: allow row tab become top-level tab
// Dashboard does not allow top-level tab become nested tab, to avoid
// nested tab inside nested tab.
source.type === TABS_TYPE &&
destination.type === TABS_TYPE &&
source.id === rootChildId &&
destination.id !== rootChildId
) {
return dispatch(
addWarningToast(t('Can not move top level tab into nested tabs')),
);
} else if (
destination &&
source &&
!(
// ensure it has moved
(destination.id === source.id && destination.index === source.index)
)
) {
dispatch(moveComponent(dropResult));
}
// call getState() again down here in case redux state is stale after
// previous dispatch(es)
const { dashboardFilters, dashboardLayout: undoableLayout } = getState();
// if we moved a child from a Tab or Row parent and it was the only child, delete the parent.
if (!isNewComponent) {
const { present: layout } = undoableLayout;
const sourceComponent = layout[source.id] || {};
const destinationComponent = layout[destination.id] || {};
if (
(sourceComponent.type === TABS_TYPE ||
sourceComponent.type === ROW_TYPE) &&
sourceComponent.children &&
sourceComponent.children.length === 0
) {
const parentId = findParentId({
childId: source.id,
layout,
});
dispatch(deleteComponent(source.id, parentId));
}
// show warning if item has been moved between different scope
if (
isInDifferentFilterScopes({
dashboardFilters,
source: (sourceComponent.parents || []).concat(source.id),
destination: (destinationComponent.parents || []).concat(
destination.id,
),
})
) {
dispatch(
addWarningToast(
t('This chart has been moved to a different filter scope.'),
),
);
}
}
return null;
};
}