Skip to content

Commit

Permalink
feat: Duplicate dashboard visualize (opensearch-project#148)
Browse files Browse the repository at this point in the history
* rename copy to duplicate

Signed-off-by: yuye-aws <[email protected]>

* duplicate in visualization

Signed-off-by: yuye-aws <[email protected]>

* duplicate in dashboard

Signed-off-by: yuye-aws <[email protected]>

* resolve conflict

Signed-off-by: yuye-aws <[email protected]>

* update test and snapshots

Signed-off-by: yuye-aws <[email protected]>

* re-duplicate if some objects cannot be duplicated

Signed-off-by: yuye-aws <[email protected]>

* remove clone for dashboard

Signed-off-by: yuye-aws <[email protected]>

* rename duplicateState to duplicateMode

Signed-off-by: yuye-aws <[email protected]>

* change workspace prop to currentWorkspace in SavedObjectsDuplicateModal

Signed-off-by: yuye-aws <[email protected]>

* change wording

Signed-off-by: yuye-aws <[email protected]>

* move duplicate modal to saved_objects for reuse

Signed-off-by: yuye-aws <[email protected]>

* move duplicate modal to saved objects management for reuse

Signed-off-by: yuye-aws <[email protected]>

* remove minimal duplicate modal props logic

Signed-off-by: yuye-aws <[email protected]>

* refactor duplicate modal props for dashboard and visualization

Signed-off-by: yuye-aws <[email protected]>

* Update getDuplicateWorkspaces function

Co-authored-by: Yulong Ruan <[email protected]>

* update function onDuplicate for dashboard

Signed-off-by: yuye-aws <[email protected]>

* Update doDuplicate for visualization

Co-authored-by: Yulong Ruan <[email protected]>

* refactor function getDuplicateWorkspaces

Signed-off-by: yuye-aws <[email protected]>

* add i18n context to saved objects table duplicate modal

Signed-off-by: yuye-aws <[email protected]>

* refactor duplicate modal logic in saved object table

Signed-off-by: yuye-aws <[email protected]>

* add error message for partial duplicate failed

Signed-off-by: yuye-aws <[email protected]>

* merge commits

Signed-off-by: yuye-aws <[email protected]>

* add type info for dashboard and visualization

Signed-off-by: yuye-aws <[email protected]>

* remote create vis reference logic

Signed-off-by: yuye-aws <[email protected]>

* Revert "remove clone for dashboard"

This reverts commit 84f77fb.

* hide duplicate when workspace disabled in dashboard

Signed-off-by: yuye-aws <[email protected]>

* feat: skip permission validate when no workspaces and permissions attributes (opensearch-project#163)

* feat: skip permission validate when saved object without workspaces and permissions attributes

Signed-off-by: Lin Wang <[email protected]>

* feat: add annontation to skip permission check

Signed-off-by: Lin Wang <[email protected]>

* refactor: remove bind and simplify validate logic

Signed-off-by: Lin Wang <[email protected]>

* feat: remove library write for object based ACL

Signed-off-by: Lin Wang <[email protected]>

---------

Signed-off-by: Lin Wang <[email protected]>

* remove get workspaces with write permission logic and add readonly props to workspace attribute

Signed-off-by: yuye-aws <[email protected]>

* change type definition logic

Signed-off-by: yuye-aws <[email protected]>

* Fix typo (opensearch-project#176)

---------

Signed-off-by: Yulong Ruan <[email protected]>

* remove exit workspace logic (opensearch-project#179)

Signed-off-by: yuye-aws <[email protected]>

* rename copy to duplicate

Signed-off-by: yuye-aws <[email protected]>

* duplicate in visualization

Signed-off-by: yuye-aws <[email protected]>

* duplicate in dashboard

Signed-off-by: yuye-aws <[email protected]>

* resolve conflict

Signed-off-by: yuye-aws <[email protected]>

* update test and snapshots

Signed-off-by: yuye-aws <[email protected]>

* re-duplicate if some objects cannot be duplicated

Signed-off-by: yuye-aws <[email protected]>

* remove clone for dashboard

Signed-off-by: yuye-aws <[email protected]>

* rename duplicateState to duplicateMode

Signed-off-by: yuye-aws <[email protected]>

* change workspace prop to currentWorkspace in SavedObjectsDuplicateModal

Signed-off-by: yuye-aws <[email protected]>

* change wording

Signed-off-by: yuye-aws <[email protected]>

* move duplicate modal to saved_objects for reuse

Signed-off-by: yuye-aws <[email protected]>

* move duplicate modal to saved objects management for reuse

Signed-off-by: yuye-aws <[email protected]>

* remove minimal duplicate modal props logic

Signed-off-by: yuye-aws <[email protected]>

* refactor duplicate modal props for dashboard and visualization

Signed-off-by: yuye-aws <[email protected]>

* Update getDuplicateWorkspaces function

Co-authored-by: Yulong Ruan <[email protected]>

* update function onDuplicate for dashboard

Signed-off-by: yuye-aws <[email protected]>

* Update doDuplicate for visualization

Co-authored-by: Yulong Ruan <[email protected]>

* refactor function getDuplicateWorkspaces

Signed-off-by: yuye-aws <[email protected]>

* add i18n context to saved objects table duplicate modal

Signed-off-by: yuye-aws <[email protected]>

* refactor duplicate modal logic in saved object table

Signed-off-by: yuye-aws <[email protected]>

* add error message for partial duplicate failed

Signed-off-by: yuye-aws <[email protected]>

* merge commits

Signed-off-by: yuye-aws <[email protected]>

* add type info for dashboard and visualization

Signed-off-by: yuye-aws <[email protected]>

* remote create vis reference logic

Signed-off-by: yuye-aws <[email protected]>

* Revert "remove clone for dashboard"

This reverts commit 84f77fb.

* hide duplicate when workspace disabled in dashboard

Signed-off-by: yuye-aws <[email protected]>

* remove get workspaces with write permission logic and add readonly props to workspace attribute

Signed-off-by: yuye-aws <[email protected]>

* change type definition logic

Signed-off-by: yuye-aws <[email protected]>

* rename variable and function name

Signed-off-by: yuye-aws <[email protected]>

* change permission mode to get target workspaces when duplicate

Signed-off-by: yuye-aws <[email protected]>

---------

Signed-off-by: yuye-aws <[email protected]>
Signed-off-by: Lin Wang <[email protected]>
Signed-off-by: Yulong Ruan <[email protected]>
Co-authored-by: Yulong Ruan <[email protected]>
Co-authored-by: Lin Wang <[email protected]>
Co-authored-by: Yulong Ruan <[email protected]>
  • Loading branch information
4 people authored Sep 20, 2023
1 parent 4bccdea commit ccd0520
Show file tree
Hide file tree
Showing 27 changed files with 506 additions and 238 deletions.
5 changes: 3 additions & 2 deletions src/core/public/workspace/workspaces_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ type WorkspaceMenuRenderFn = ({
observables: WorkspaceObservables;
}) => JSX.Element | null;

type WorkspaceObject = WorkspaceAttribute & { libraryReadonly?: boolean };
export interface WorkspaceObservables {
currentWorkspaceId$: BehaviorSubject<string>;
currentWorkspace$: BehaviorSubject<WorkspaceAttribute | null>;
workspaceList$: BehaviorSubject<WorkspaceAttribute[]>;
currentWorkspace$: BehaviorSubject<WorkspaceObject | null>;
workspaceList$: BehaviorSubject<WorkspaceObject[]>;
workspaceEnabled$: BehaviorSubject<boolean>;
initialized$: BehaviorSubject<boolean>;
}
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/dashboard/opensearch_dashboards.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
"optionalPlugins": ["home", "share", "usageCollection"],
"server": true,
"ui": true,
"requiredBundles": ["opensearchDashboardsUtils", "opensearchDashboardsReact", "home"]
"requiredBundles": ["opensearchDashboardsUtils", "opensearchDashboardsReact", "home", "savedObjectsManagement"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ const TopNav = ({
getTopNavConfig(
currentAppState?.viewMode,
navActions,
dashboardConfig.getHideWriteControls()
dashboardConfig.getHideWriteControls(),
services.workspaces.workspaceEnabled$.value
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ import { NavAction } from '../../../../types';
export function getTopNavConfig(
dashboardMode: ViewMode,
actions: { [key: string]: NavAction },
hideWriteControls: boolean
hideWriteControls: boolean,
workspaceEnabled?: boolean
) {
switch (dashboardMode) {
case ViewMode.VIEW:
Expand All @@ -54,7 +55,9 @@ export function getTopNavConfig(
: [
getFullScreenConfig(actions[TopNavIds.FULL_SCREEN]),
getShareConfig(actions[TopNavIds.SHARE]),
getCloneConfig(actions[TopNavIds.CLONE]),
...(workspaceEnabled
? [getDuplicateConfig(actions[TopNavIds.DUPLICATE])]
: [getCloneConfig(actions[TopNavIds.CLONE])]),
getEditConfig(actions[TopNavIds.ENTER_EDIT_MODE]),
];
case ViewMode.EDIT:
Expand Down Expand Up @@ -158,6 +161,23 @@ function getCloneConfig(action: NavAction) {
};
}

/**
* @returns {osdTopNavConfig}
*/
function getDuplicateConfig(action: NavAction) {
return {
id: 'duplicate',
label: i18n.translate('dashboard.topNave.duplicateButtonAriaLabel', {
defaultMessage: 'Duplicate',
}),
description: i18n.translate('dashboard.topNave.duplicateConfigDescription', {
defaultMessage: 'Duplicate your dashboard',
}),
testId: 'dashboardDuplicate',
run: action,
};
}

/**
* @returns {osdTopNavConfig}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const TopNavIds = {
EXIT_EDIT_MODE: 'exitEditMode',
ENTER_EDIT_MODE: 'enterEditMode',
CLONE: 'clone',
DUPLICATE: 'duplicate',
FULL_SCREEN: 'fullScreenMode',
VISUALIZE: 'visualize',
ADD_EXISTING: 'addExisting',
Expand Down
74 changes: 68 additions & 6 deletions src/plugins/dashboard/public/application/utils/get_nav_actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { i18n } from '@osd/i18n';
import { EUI_MODAL_CANCEL_BUTTON, EuiCheckboxGroup } from '@elastic/eui';
import { EuiCheckboxGroupIdToSelectedMap } from '@elastic/eui/src/components/form/checkbox/checkbox_group';
import {
SaveResult,
SavedObjectSaveOpts,
getSavedObjectFinder,
SavedObjectSaveOpts,
SaveResult,
showSaveModal,
} from '../../../../saved_objects/public';
import { DashboardAppStateContainer, DashboardServices, NavAction } from '../../types';
Expand All @@ -24,15 +24,21 @@ import {
import {
EmbeddableFactoryNotFoundError,
EmbeddableInput,
ViewMode,
isErrorEmbeddable,
openAddPanelFlyout,
ViewMode,
} from '../../../../embeddable/public';
import { saveDashboard } from '../utils';
import { DashboardContainer } from '../embeddable/dashboard_container';
import { DashboardConstants, createDashboardEditUrl } from '../../dashboard_constants';
import { createDashboardEditUrl, DashboardConstants } from '../../dashboard_constants';
import { unhashUrl } from '../../../../opensearch_dashboards_utils/public';
import { Dashboard } from '../../dashboard';
import { SavedObjectWithMetadata } from '../../../../saved_objects_management/common';
import {
DuplicateMode,
showDuplicateModal,
duplicateSavedObjects,
} from '../../../../saved_objects_management/public';

interface UrlParamsSelectedMap {
[UrlParams.SHOW_TOP_MENU]: boolean;
Expand Down Expand Up @@ -65,10 +71,13 @@ export const getNavActions = (
share,
dashboardConfig,
dashboardCapabilities,
http,
workspaces,
} = services;
const navActions: {
[key: string]: NavAction;
} = {};
const workspaceEnabled = workspaces.workspaceEnabled$.value;

if (!stateContainer) {
return navActions;
Expand Down Expand Up @@ -133,7 +142,7 @@ export const getNavActions = (
title={currentTitle}
description={currentDescription}
timeRestore={currentTimeRestore}
showCopyOnSave={savedDashboard.id ? true : false}
showCopyOnSave={!!savedDashboard.id}
/>
);
showSaveModal(dashboardSaveModal, I18nContext);
Expand Down Expand Up @@ -166,6 +175,59 @@ export const getNavActions = (
showCloneModal(onClone, currentTitle);
};

if (workspaceEnabled) {
navActions[TopNavIds.DUPLICATE] = () => {
const onDuplicate = async (
dashboardSavedObjects: SavedObjectWithMetadata[],
includeReferencesDeep: boolean,
targetWorkspace: string
) => {
const objectsToDuplicate = dashboardSavedObjects.map((obj) => ({
id: obj.id,
type: obj.type,
}));

try {
await duplicateSavedObjects(
http,
objectsToDuplicate,
includeReferencesDeep,
targetWorkspace
);

notifications.toasts.addSuccess({
title: i18n.translate('dashboard.dashboardWasDuplicatedSuccessMessage', {
defaultMessage: 'Duplicate dashboard successfully',
}),
});
} catch (e) {
notifications.toasts.addDanger({
title: i18n.translate('dashboard.dashboardWasNotDuplicatedDangerMessage', {
defaultMessage: 'Unable to duplicate dashboard',
}),
});
}
};

const dashboardSavedObject = ({
...currentContainer,
...savedDashboard,
} as unknown) as SavedObjectWithMetadata;
dashboardSavedObject.meta = { title: savedDashboard.title };

const showDuplicateModalProps = {
http,
workspaces,
onDuplicate,
notifications,
duplicateMode: DuplicateMode.Selected,
selectedSavedObjects: [dashboardSavedObject],
};

showDuplicateModal(showDuplicateModalProps, I18nContext);
};
}

navActions[TopNavIds.ADD_EXISTING] = () => {
if (currentContainer && !isErrorEmbeddable(currentContainer)) {
openAddPanelFlyout({
Expand Down Expand Up @@ -203,7 +265,7 @@ export const getNavActions = (
};

if (share) {
// the share button is only availabale if "share" plugin contract enabled
// the share button is only available if "share" plugin contract enabled
navActions[TopNavIds.SHARE] = (anchorElement) => {
const EmbedUrlParamExtension = ({
setParamValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null {
}

function renderSearchBar(): ReactElement | null {
// Validate presense of all required fields
// Validate presence of all required fields
if (!showSearchBar || !props.data) return null;
const { SearchBar } = props.data.ui;
return <SearchBar {...searchBarProps} />;
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/saved_objects_management/public/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ export const SAVED_QUERIES_WORDINGS = i18n.translate(
}
);

export const SAVED_OBJECT_TYPE_WORKSAPCE = 'workspace';
export const SAVED_OBJECT_TYPE_WORKSPACE = 'workspace';
15 changes: 13 additions & 2 deletions src/plugins/saved_objects_management/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,22 @@ export {
ISavedObjectsManagementServiceRegistry,
SavedObjectsManagementServiceRegistryEntry,
} from './services';
export { ProcessedImportResponse, processImportResponse, FailedImport } from './lib';
export {
ProcessedImportResponse,
processImportResponse,
FailedImport,
duplicateSavedObjects,
getSavedObjectLabel,
} from './lib';
export { SavedObjectRelation, SavedObjectWithMetadata, SavedObjectMetadata } from './types';
export { SAVED_OBJECT_DELETE_TRIGGER, savedObjectDeleteTrigger } from './triggers';
export { SavedObjectDeleteContext } from './ui_actions_bootstrap';

export { SAVED_OBJECT_TYPE_WORKSPACE } from './constants';
export {
showDuplicateModal,
SavedObjectsDuplicateModal,
DuplicateMode,
} from './management_section';
export function plugin(initializerContext: PluginInitializerContext) {
return new SavedObjectsManagementPlugin();
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import { HttpStart } from 'src/core/public';

export async function copySavedObjects(
export async function duplicateSavedObjects(
http: HttpStart,
objects: any[],
includeReferencesDeep: boolean = true,
Expand Down

This file was deleted.

3 changes: 1 addition & 2 deletions src/plugins/saved_objects_management/public/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,4 @@ export { extractExportDetails, SavedObjectsExportResultDetails } from './extract
export { createFieldList } from './create_field_list';
export { getAllowedTypes } from './get_allowed_types';
export { filterQuery } from './filter_query';
export { copySavedObjects } from './copy_saved_objects';
export { getWorkspacesWithWritePermission } from './get_workspaces_with_write_permission';
export { duplicateSavedObjects } from './duplicate_saved_objects';
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@
*/

export { mountManagementSection } from './mount_section';
export { showDuplicateModal, SavedObjectsDuplicateModal, DuplicateMode } from './objects_table';

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ccd0520

Please sign in to comment.