Skip to content

Commit

Permalink
Added confirm modal for saving shared dashbaords
Browse files Browse the repository at this point in the history
  • Loading branch information
cqliu1 committed Nov 11, 2023
1 parent a130ed0 commit 3bc73c3
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,23 @@ export const useDashboardMenuItems = ({
isLabsShown,
setIsLabsShown,
showResetChange,
confirmSaveForSharedDashboard,
updateSpacesForReferences,
}: {
redirectTo: DashboardRedirect;
isLabsShown: boolean;
setIsLabsShown: Dispatch<SetStateAction<boolean>>;
showResetChange?: boolean;
updateSpacesForReferences: () => void;
confirmSaveForSharedDashboard: ({
onSave,
onCancel,
onClone,
}: {
onSave: () => void;
onClone: () => void;
onCancel?: () => void;
}) => void;
}) => {
const [isSaveInProgress, setIsSaveInProgress] = useState(false);

Expand All @@ -45,6 +55,7 @@ export const useDashboardMenuItems = ({
dashboardBackup,
settings: { uiSettings },
dashboardCapabilities: { showWriteControls },
spaces: { spacesApi },
} = pluginServices.getServices();
const isLabsEnabled = uiSettings.get(UI_SETTINGS.ENABLE_LABS_UI);

Expand All @@ -61,11 +72,14 @@ export const useDashboardMenuItems = ({
const lastSavedId = dashboard.select((state) => state.componentState.lastSavedId);
const namespaces = dashboard.select((state) => state.componentState.namespaces);
const dashboardTitle = dashboard.select((state) => state.explicitInput.title);
const dashboardId = dashboard.select((state) => state.explicitInput.id);
const viewMode = dashboard.select((state) => state.explicitInput.viewMode);
const managed = dashboard.select((state) => state.componentState.managed);
const disableTopNav = isSaveInProgress || hasOverlays;

const isShared = spacesApi && lastSavedId && namespaces && namespaces.length > 1;

console.log({ isShared });

/**
* Show the Dashboard app's share menu
*/
Expand Down Expand Up @@ -97,27 +111,6 @@ export const useDashboardMenuItems = ({
[redirectTo]
);

/**
* Save the dashboard without any UI or popups.
*/
const quickSaveDashboard = useCallback(() => {
setIsSaveInProgress(true);
dashboard.runQuickSave().then(() => {
updateSpacesForReferences();
setTimeout(() => setIsSaveInProgress(false), CHANGE_CHECK_DEBOUNCE);
});
}, [dashboard, updateSpacesForReferences]);

/**
* Show the dashboard's save modal
*/
const saveDashboardAs = useCallback(() => {
dashboard.runSaveAs().then((result) => {
updateSpacesForReferences();
maybeRedirect(result);
});
}, [dashboard, updateSpacesForReferences, maybeRedirect]);

/**
* Clone the dashboard
*/
Expand All @@ -130,6 +123,56 @@ export const useDashboardMenuItems = ({
});
}, [maybeRedirect, dashboard]);

/**
* Save the dashboard without any UI or popups.
*/
const quickSaveDashboard = useCallback(() => {
if (isShared) {
confirmSaveForSharedDashboard({
onSave: () => {
setIsSaveInProgress(true);
dashboard.runQuickSave().then(() => {
updateSpacesForReferences();
setTimeout(() => setIsSaveInProgress(false), CHANGE_CHECK_DEBOUNCE);
});
},
onClone: clone,
});
} else {
dashboard.runQuickSave().then(() => {
setTimeout(() => setIsSaveInProgress(false), CHANGE_CHECK_DEBOUNCE);
});
}
}, [clone, confirmSaveForSharedDashboard, dashboard, isShared, updateSpacesForReferences]);

/**
* Show the dashboard's save modal
*/
const saveDashboardAs = useCallback(() => {
if (isShared) {
confirmSaveForSharedDashboard({
onSave: () => {
dashboard.runSaveAs().then((result) => {
updateSpacesForReferences();
maybeRedirect(result);
});
},
onClone: clone,
});
} else {
dashboard.runSaveAs().then((result) => {
maybeRedirect(result);
});
}
}, [
isShared,
confirmSaveForSharedDashboard,
clone,
dashboard,
updateSpacesForReferences,
maybeRedirect,
]);

/**
* Show the dashboard's "Confirm reset changes" modal. If confirmed:
* (1) reset the dashboard to the last saved state, and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,24 @@ import {
import { ViewMode } from '@kbn/embeddable-plugin/public';
import type { DataView } from '@kbn/data-views-plugin/public';
import { TopNavMenuProps } from '@kbn/navigation-plugin/public';
import { EuiHorizontalRule, EuiIcon, EuiToolTipProps } from '@elastic/eui';
import {
EuiButton,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiIcon,
EuiModal,
EuiModalBody,
EuiModalFooter,
EuiModalHeader,
EuiText,
EuiTitle,
EuiToolTipProps,
} from '@elastic/eui';
import { EuiBreadcrumbProps } from '@elastic/eui/src/components/breadcrumbs/breadcrumb';
import { MountPoint } from '@kbn/core/public';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import { SpacesContextProps } from '@kbn/spaces-plugin/public';
import {
getDashboardTitle,
leaveConfirmStrings,
Expand All @@ -38,6 +53,8 @@ import { getFullEditPath, LEGACY_DASHBOARD_APP_ID } from '../dashboard_constants
import './_dashboard_top_nav.scss';
import { DashboardRedirect } from '../dashboard_container/types';

const getEmptyFunctionComponent: React.FC<SpacesContextProps> = ({ children }) => <>{children}</>;

export interface InternalDashboardTopNavProps {
customLeadingBreadCrumbs?: EuiBreadcrumbProps[];
embedSettings?: DashboardEmbedSettings;
Expand Down Expand Up @@ -75,6 +92,7 @@ export function InternalDashboardTopNav({
setIsVisible: setChromeVisibility,
getIsVisible$: getChromeIsVisible$,
recentlyAccessed: chromeRecentlyAccessed,
theme: { theme$ },
},
serverless,
settings: { uiSettings },
Expand All @@ -83,8 +101,11 @@ export function InternalDashboardTopNav({
initializerContext: { allowByValueEmbeddables },
dashboardCapabilities: { saveQuery: allowSaveQuery, showWriteControls },
spaces: { spacesApi },
overlays: { openModal },
} = pluginServices.getServices();
const spacesService = spacesApi?.ui.useSpaces();
const SpacesContextWrapper =
spacesApi?.ui.components.getSpacesContextProvider ?? getEmptyFunctionComponent;

const isLabsEnabled = uiSettings.get(UI_SETTINGS.ENABLE_LABS_UI);
const { setHeaderActionMenu, onAppLeave } = useDashboardMountContext();
Expand Down Expand Up @@ -270,8 +291,101 @@ export function InternalDashboardTopNav({
viewMode,
]);

const confirmSaveForSharedDashboard = useCallback(
async ({
onSave,
onClone,
onCancel,
}: {
onSave: () => void;
onClone: () => void;
onCancel?: () => void;
}) => {
if (!spacesApi || !lastSavedId || !namespaces || namespaces.length < 2) return;

const { spacesManager } = spacesService;
// const spacesPermissions = await spacesManager.getSpaces({
// purpose: 'shareSavedObjectsIntoSpace',
// includeAuthorizedPurposes: true,
// });
// console.log({ spacesPermissions });

const insufficientPermissions = namespaces.includes('?');

const session = openModal(
toMountPoint(
<SpacesContextWrapper>
<EuiModal onClose={() => session.close()}>
<EuiModalHeader>
<EuiTitle>
<h1>Save changes?</h1>
</EuiTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiText>
<p>You are attempting to save changes to a dashboard shared in these spaces:</p>
</EuiText>
{spacesApi?.ui.components.getSpaceList({ namespaces })}
</EuiModalBody>
<EuiModalFooter>
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiButton
color="danger"
onClick={() => {
if (onCancel) onCancel();
session.close();
}}
>
Cancel
</EuiButton>
</EuiFlexItem>
<EuiFlexItem />
<EuiFlexItem grow={false}>
<EuiButton
color="primary"
fill={insufficientPermissions}
onClick={() => {
onClone();
session.close();
}}
>
Clone & Save
</EuiButton>
</EuiFlexItem>
{!insufficientPermissions ? (
<EuiFlexItem grow={false}>
<EuiButton
color="primary"
fill
onClick={() => {
onSave();
session.close();
}}
>
Share & Save
</EuiButton>
</EuiFlexItem>
) : null}
</EuiFlexGroup>
</EuiModalFooter>
</EuiModal>
</SpacesContextWrapper>,
{
theme$,
}
),
{
maxWidth: 400,
'data-test-subj': 'copyToDashboardPanel',
}
);
},
[SpacesContextWrapper, lastSavedId, namespaces, openModal, spacesApi, spacesService, theme$]
);

const updateSpacesForReferences = useCallback(async () => {
if (!spacesService || !lastSavedId || !namespaces?.length) return;
if (!spacesService || !lastSavedId || !namespaces || namespaces.length < 2) return;

const { spacesManager } = spacesService;

Expand All @@ -280,6 +394,9 @@ export function InternalDashboardTopNav({
]);
const objects = shareableReferences.objects.map(({ id, type }) => ({ id, type }));

if (namespaces?.includes('?')) {
// User doesn't have any access to one of the shared spaces
}
spacesManager.updateSavedObjectsSpaces(objects, namespaces, []);
}, [lastSavedId, namespaces, spacesService]);

Expand All @@ -289,6 +406,7 @@ export function InternalDashboardTopNav({
setIsLabsShown,
showResetChange,
updateSpacesForReferences,
confirmSaveForSharedDashboard,
});

UseUnmount(() => {
Expand Down

0 comments on commit 3bc73c3

Please sign in to comment.