From d9c4845adb54d274a75ef234855c6ea5a4328c82 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Wed, 7 Aug 2024 16:41:37 +0800 Subject: [PATCH 01/20] navigates to use case overview page Signed-off-by: Hailong Cui --- .../service_card/workspace_list_card.tsx | 18 +++++++++++++---- .../public/components/utils/workspace.ts | 20 ++++++++++++++++--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx b/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx index 009f6519ce8f..a267ab5a176b 100644 --- a/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx +++ b/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx @@ -22,11 +22,13 @@ import { import { i18n } from '@osd/i18n'; import moment from 'moment'; import { orderBy } from 'lodash'; -import { CoreStart, WorkspaceObject } from '../../../../../core/public'; -import { navigateToWorkspaceDetail } from '../utils/workspace'; +import { useObservable } from 'react-use'; +import { CoreStart, WorkspaceAvailability, WorkspaceObject } from '../../../../../core/public'; import { WORKSPACE_CREATE_APP_ID, WORKSPACE_LIST_APP_ID } from '../../../common/constants'; import { recentWorkspaceManager } from '../../recent_workspace_manager'; +import { getFirstUseCaseOfFeatureConfigs } from '../../utils'; +import { navigateToAppWithinWorkspace } from '../utils/workspace'; const WORKSPACE_LIST_CARD_DESCRIPTION = i18n.translate('workspace.list.card.description', { defaultMessage: @@ -42,6 +44,7 @@ export interface WorkspaceListCardProps { export const WorkspaceListCard = (props: WorkspaceListCardProps) => { const [availableWorkspaces, setAvailableWorkspaces] = useState([]); const [filter, setFilter] = useState('viewed'); + const navGroups = useObservable(props.core.chrome.navGroup.getNavGroupsMap$()); useEffect(() => { const workspaceSub = props.core.workspaces.workspaceList$.subscribe((list) => { @@ -77,8 +80,15 @@ export const WorkspaceListCard = (props: WorkspaceListCardProps) => { const handleSwitchWorkspace = (id: string) => { const { application, http } = props.core; - if (application && http) { - navigateToWorkspaceDetail({ application, http }, id); + const workspaceObj = availableWorkspaces.find((item) => item.id === id); + const useCase = getFirstUseCaseOfFeatureConfigs(workspaceObj?.features || []); + if (useCase && navGroups) { + // should be workspace use case overview page + const availableLinks = navGroups[useCase].navLinks?.filter( + (navLink) => navLink.workspaceAvailability !== WorkspaceAvailability.outsideWorkspace + ); + const appId = availableLinks?.[0].id; + navigateToAppWithinWorkspace({ application, http }, id, appId); } }; diff --git a/src/plugins/workspace/public/components/utils/workspace.ts b/src/plugins/workspace/public/components/utils/workspace.ts index 3acd26570f59..587061fe9f9d 100644 --- a/src/plugins/workspace/public/components/utils/workspace.ts +++ b/src/plugins/workspace/public/components/utils/workspace.ts @@ -14,17 +14,31 @@ export const navigateToWorkspaceDetail = ( { application, http }: Core, id: string, tabId: string = DetailTab.Details +) => { + navigateToAppWithinWorkspace( + { application, http }, + id, + WORKSPACE_DETAIL_APP_ID, + `/?tab=${tabId}` + ); +}; + +export const navigateToAppWithinWorkspace = ( + { application, http }: Core, + workspaceId: string, + appId: string, + hash: string ) => { const newUrl = formatUrlWithWorkspaceId( - application.getUrlForApp(WORKSPACE_DETAIL_APP_ID, { + application.getUrlForApp(appId, { absolute: true, }), - id, + workspaceId, http.basePath ); if (newUrl) { const url = new URL(newUrl); - url.hash = `/?tab=${tabId}`; + url.hash = hash; application.navigateToUrl(url.toString()); } }; From 07348e11eb7f9458a78d78bcdd10da120245696b Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Fri, 9 Aug 2024 18:06:18 +0800 Subject: [PATCH 02/20] Essential use case overviea page Signed-off-by: Hailong Cui Changeset file for PR #7673 created/updated Signed-off-by: Hailong Cui Revert "navigates to use case overview page" This reverts commit a43f533c4086cc742bd018ffa7a79a909e508897. Signed-off-by: Hailong Cui --- changelogs/fragments/7673.yml | 2 + .../card_container/card_embeddable.tsx | 4 +- .../components/card_container/card_list.tsx | 7 +- .../public/components/card_container/types.ts | 2 + .../public/components/section_input.ts | 1 + .../public/components/section_render.tsx | 33 +++-- .../content_management_service.ts | 23 ++-- .../services/content_management/types.ts | 5 +- .../sample_data/sample_data_card.tsx | 40 ++++++ src/plugins/home/public/index.ts | 6 + src/plugins/home/public/plugin.ts | 4 + .../saved_objects_management/public/plugin.ts | 6 +- src/plugins/workspace/common/constants.ts | 21 +++ src/plugins/workspace/public/application.tsx | 17 +++ .../service_card/workspace_list_card.tsx | 18 +-- .../use_case_overview/get_started_cards.tsx | 73 +++++++++++ .../components/use_case_overview/index.ts | 6 + .../use_case_overview/setup_overview.tsx | 122 ++++++++++++++++++ .../workspace_use_case_overview_app.tsx | 25 ++++ src/plugins/workspace/public/plugin.ts | 66 +++++++++- src/plugins/workspace/public/types.ts | 2 + 21 files changed, 438 insertions(+), 45 deletions(-) create mode 100644 changelogs/fragments/7673.yml create mode 100644 src/plugins/home/public/application/components/sample_data/sample_data_card.tsx create mode 100644 src/plugins/workspace/public/components/use_case_overview/get_started_cards.tsx create mode 100644 src/plugins/workspace/public/components/use_case_overview/index.ts create mode 100644 src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx create mode 100644 src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx diff --git a/changelogs/fragments/7673.yml b/changelogs/fragments/7673.yml new file mode 100644 index 000000000000..2bbd360048a4 --- /dev/null +++ b/changelogs/fragments/7673.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace]Essential use case overview page ([#7673](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7673)) \ No newline at end of file diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable.tsx b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx index 588ce1681957..914fb91b76e7 100644 --- a/src/plugins/content_management/public/components/card_container/card_embeddable.tsx +++ b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx @@ -7,6 +7,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { EuiCard } from '@elastic/eui'; +import { EuiCardSelectProps } from '@elastic/eui/src/components/card/card_select'; import { Embeddable, EmbeddableInput, IContainer } from '../../../../embeddable/public'; export const CARD_EMBEDDABLE = 'card_embeddable'; @@ -15,6 +16,7 @@ export type CardEmbeddableInput = EmbeddableInput & { onClick?: () => void; getIcon?: () => React.ReactElement; getFooter?: () => React.ReactElement; + selectable?: EuiCardSelectProps; }; export class CardEmbeddable extends Embeddable { @@ -35,10 +37,10 @@ export class CardEmbeddable extends Embeddable { textAlign="left" title={this.input.title ?? ''} description={this.input.description} - display="plain" onClick={this.input.onClick} icon={this.input?.getIcon?.()} footer={this.input?.getFooter?.()} + selectable={this.input.selectable} />, node ); diff --git a/src/plugins/content_management/public/components/card_container/card_list.tsx b/src/plugins/content_management/public/components/card_container/card_list.tsx index 871c6451a8cb..da042b54d45e 100644 --- a/src/plugins/content_management/public/components/card_container/card_list.tsx +++ b/src/plugins/content_management/public/components/card_container/card_list.tsx @@ -26,7 +26,12 @@ const CardListInner = ({ embeddable, input, embeddableServices }: Props) => { const child = embeddable.getChild(panel.explicitInput.id); return ( - + ); }); diff --git a/src/plugins/content_management/public/components/card_container/types.ts b/src/plugins/content_management/public/components/card_container/types.ts index 5c6ad129af66..2b758d22ae23 100644 --- a/src/plugins/content_management/public/components/card_container/types.ts +++ b/src/plugins/content_management/public/components/card_container/types.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { EuiCardSelectProps } from '@elastic/eui/src/components/card/card_select'; import { ContainerInput } from '../../../../embeddable/public'; export interface CardExplicitInput { @@ -11,6 +12,7 @@ export interface CardExplicitInput { onClick?: () => void; getIcon?: () => React.ReactElement; getFooter?: () => React.ReactElement; + selectable?: EuiCardSelectProps; } export type CardContainerInput = ContainerInput & { columns?: number }; diff --git a/src/plugins/content_management/public/components/section_input.ts b/src/plugins/content_management/public/components/section_input.ts index 5a0b9ca370c6..aeec31b37b44 100644 --- a/src/plugins/content_management/public/components/section_input.ts +++ b/src/plugins/content_management/public/components/section_input.ts @@ -46,6 +46,7 @@ export const createCardInput = ( onClick: content.onClick, getIcon: content?.getIcon, getFooter: content?.getFooter, + selectable: content.selectable, }, }; } diff --git a/src/plugins/content_management/public/components/section_render.tsx b/src/plugins/content_management/public/components/section_render.tsx index d28fbad7296a..17da6d20b90c 100644 --- a/src/plugins/content_management/public/components/section_render.tsx +++ b/src/plugins/content_management/public/components/section_render.tsx @@ -41,7 +41,12 @@ const DashboardSection = ({ section, embeddable, contents$, savedObjectsClient } if (section.kind === 'dashboard' && factory && input) { // const input = createDashboardSection(section, contents ?? []); - return ; + return ( + // to make dashboard section align with others add margin left -8px +
+ +
+ ); } return null; @@ -61,18 +66,20 @@ const CardSection = ({ section, embeddable, contents$ }: Props) => { if (section.kind === 'card' && factory && input) { return ( - - -

- - {section.title} -

-
+ + {section.title ? ( + +

+ + {section.title} +

+
+ ) : null} {isCardVisible && ( <> diff --git a/src/plugins/content_management/public/services/content_management/content_management_service.ts b/src/plugins/content_management/public/services/content_management/content_management_service.ts index 1c12ad826f56..c1a2f84a54d0 100644 --- a/src/plugins/content_management/public/services/content_management/content_management_service.ts +++ b/src/plugins/content_management/public/services/content_management/content_management_service.ts @@ -35,16 +35,19 @@ export class ContentManagementService { registerContentProvider = (provider: ContentProvider) => { this.contentProviders.set(provider.id, provider); - const targetArea = provider.getTargetArea(); - const [pageId, sectionId] = targetArea.split('/'); - - if (!pageId || !sectionId) { - throw new Error('getTargetArea() should return a string in format {pageId}/{sectionId}'); - } - - const page = this.getPage(pageId); - if (page) { - page.addContent(sectionId, provider.getContent()); + const area = provider.getTargetArea(); + const targetAreas: string[] = Array.isArray(area) ? [...area] : [area]; + for (const targetArea of targetAreas) { + const [pageId, sectionId] = targetArea.split('/'); + + if (!pageId || !sectionId) { + throw new Error('getTargetArea() should return a string in format {pageId}/{sectionId}'); + } + + const page = this.getPage(pageId); + if (page) { + page.addContent(sectionId, provider.getContent()); + } } }; diff --git a/src/plugins/content_management/public/services/content_management/types.ts b/src/plugins/content_management/public/services/content_management/types.ts index 5b9b4662d37f..a073f6ef3f85 100644 --- a/src/plugins/content_management/public/services/content_management/types.ts +++ b/src/plugins/content_management/public/services/content_management/types.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { EuiCardSelectProps } from '@elastic/eui/src/components/card/card_select'; import { CardContainerExplicitInput } from '../../components/card_container/types'; import { DashboardContainerExplicitInput } from '../../components/types'; @@ -51,6 +52,7 @@ export type Content = id: string; order: number; input: SavedObjectInput; + width: number; } | { kind: 'custom'; @@ -67,6 +69,7 @@ export type Content = onClick?: () => void; getIcon?: () => React.ReactElement; getFooter?: () => React.ReactElement; + selectable?: EuiCardSelectProps; }; export type SavedObjectInput = @@ -88,5 +91,5 @@ export type SavedObjectInput = export interface ContentProvider { id: string; getContent: () => Content; - getTargetArea: () => string; + getTargetArea: () => string | string[]; } diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx new file mode 100644 index 000000000000..42fa82b2f84e --- /dev/null +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx @@ -0,0 +1,40 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreStart } from 'opensearch-dashboards/public'; +import React from 'react'; +import { EuiI18n } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { ContentManagementPluginStart } from '../../../../../content_management/public'; +import { IMPORT_SAMPLE_DATA_APP_ID } from '../../../../common/constants'; + +export const registerSampleDataCard = ( + contentManagement: ContentManagementPluginStart, + core: CoreStart +) => { + contentManagement.registerContentProvider({ + id: `get_start_sample_data`, + getTargetArea: () => ['essential_overview/get_started'], + getContent: () => ({ + id: 'sample_data', + kind: 'card', + order: 0, + description: i18n.translate('home.sampleData.card.description', { + defaultMessage: 'Explore sample data before adding your own.', + }), + title: i18n.translate('home.sampleData.card.title', { + defaultMessage: 'Try openSearch', + }), + selectable: { + children: , + isSelected: false, + onClick: () => { + // TODO change to a modal + core.application.navigateToApp(IMPORT_SAMPLE_DATA_APP_ID); + }, + }, + }), + }); +}; diff --git a/src/plugins/home/public/index.ts b/src/plugins/home/public/index.ts index d252a31a0977..18f321fc87d3 100644 --- a/src/plugins/home/public/index.ts +++ b/src/plugins/home/public/index.ts @@ -55,3 +55,9 @@ export const plugin = (initializerContext: PluginInitializerContext) => new HomePublicPlugin(initializerContext); export { HOME_PAGE_ID, HOME_CONTENT_AREAS } from '../common/constants'; + +export { + HomeListCard, + WHATS_NEW_CONFIG, + LEARN_OPENSEARCH_CONFIG, +} from '../public/application/components/home_list_card'; diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index fe1099a8e635..68fcadf0eb0e 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -70,6 +70,7 @@ import { ContentManagementPluginStart, } from '../../content_management/public'; import { initHome, setupHome } from './application/home_render'; +import { registerSampleDataCard } from './application/components/sample_data/sample_data_card'; export interface HomePluginStartDependencies { data: DataPublicPluginStart; @@ -237,6 +238,9 @@ export class HomePublicPlugin // initialize homepage initHome(contentManagement, core); + // register sample data card to use case overview page + registerSampleDataCard(contentManagement, core); + this.featuresCatalogueRegistry.start({ capabilities }); this.sectionTypeService.start({ core, data }); diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts index 2f69c1587c65..bcbd55207cac 100644 --- a/src/plugins/saved_objects_management/public/plugin.ts +++ b/src/plugins/saved_objects_management/public/plugin.ts @@ -236,7 +236,11 @@ export class SavedObjectsManagementPlugin }), }; }, - getTargetArea: () => HOME_CONTENT_AREAS.RECENTLY_VIEWED, + getTargetArea: () => [ + HOME_CONTENT_AREAS.RECENTLY_VIEWED, + 'essential_overview/recently_viewed', + 'analytics_overview/recently_viewed', + ], }); return { diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index c8582d2439de..60812ee79401 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -11,6 +11,8 @@ export const WORKSPACE_CREATE_APP_ID = 'workspace_create'; export const WORKSPACE_LIST_APP_ID = 'workspace_list'; export const WORKSPACE_DETAIL_APP_ID = 'workspace_detail'; export const WORKSPACE_INITIAL_APP_ID = 'workspace_initial'; +export const ESSENTIAL_OVERVIEW_APP_ID = 'essential_overview'; +export const ANALYTICS_OVERVIEW_ALL_APP_ID = 'analytics_all_overview'; /** * Since every workspace always have overview and update page, these features will be selected by default * and can't be changed in the workspace form feature selector @@ -189,3 +191,22 @@ export const CURRENT_USER_PLACEHOLDER = '%me%'; export const MAX_WORKSPACE_NAME_LENGTH = 40; export const MAX_WORKSPACE_DESCRIPTION_LENGTH = 200; +export const ESSENTIAL_OVERVIEW_PAGE_ID = 'essential_overview'; +export const ANALYTICS_OVERVIEW_PAGE_ID = 'analytics_overview'; +export enum SECTIONS { + GET_STARTED = `get_started`, + SERVICE_CARDS = `service_cards`, + RECENTLY_VIEWED = `recently_viewed`, +} + +export enum ESSENTIAL_OVERVIEW_CONTENT_AREAS { + GET_STARTED = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, + SERVICE_CARDS = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, + RECENTLY_VIEWED = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, +} + +export enum ANALYTICS_OVERVIEW_CONTENT_AREAS { + GET_STARTED = `${ANALYTICS_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, + SERVICE_CARDS = `${ANALYTICS_OVERVIEW_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, + RECENTLY_VIEWED = `${ANALYTICS_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, +} diff --git a/src/plugins/workspace/public/application.tsx b/src/plugins/workspace/public/application.tsx index cbc45c938586..c975323d0fa2 100644 --- a/src/plugins/workspace/public/application.tsx +++ b/src/plugins/workspace/public/application.tsx @@ -102,3 +102,20 @@ export const renderInitialApp = ({}: AppMountParameters, services: Services) => ReactDOM.unmountComponentAtNode(rootElement!); }; }; + +export const renderOverviewApp = async ( + { element }: AppMountParameters, + services: Services, + pageId: string +) => { + ReactDOM.render( + + {services.contentManagement?.renderPage(pageId)} + , + element + ); + + return () => { + ReactDOM.unmountComponentAtNode(element); + }; +}; diff --git a/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx b/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx index a267ab5a176b..009f6519ce8f 100644 --- a/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx +++ b/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx @@ -22,13 +22,11 @@ import { import { i18n } from '@osd/i18n'; import moment from 'moment'; import { orderBy } from 'lodash'; -import { useObservable } from 'react-use'; -import { CoreStart, WorkspaceAvailability, WorkspaceObject } from '../../../../../core/public'; +import { CoreStart, WorkspaceObject } from '../../../../../core/public'; +import { navigateToWorkspaceDetail } from '../utils/workspace'; import { WORKSPACE_CREATE_APP_ID, WORKSPACE_LIST_APP_ID } from '../../../common/constants'; import { recentWorkspaceManager } from '../../recent_workspace_manager'; -import { getFirstUseCaseOfFeatureConfigs } from '../../utils'; -import { navigateToAppWithinWorkspace } from '../utils/workspace'; const WORKSPACE_LIST_CARD_DESCRIPTION = i18n.translate('workspace.list.card.description', { defaultMessage: @@ -44,7 +42,6 @@ export interface WorkspaceListCardProps { export const WorkspaceListCard = (props: WorkspaceListCardProps) => { const [availableWorkspaces, setAvailableWorkspaces] = useState([]); const [filter, setFilter] = useState('viewed'); - const navGroups = useObservable(props.core.chrome.navGroup.getNavGroupsMap$()); useEffect(() => { const workspaceSub = props.core.workspaces.workspaceList$.subscribe((list) => { @@ -80,15 +77,8 @@ export const WorkspaceListCard = (props: WorkspaceListCardProps) => { const handleSwitchWorkspace = (id: string) => { const { application, http } = props.core; - const workspaceObj = availableWorkspaces.find((item) => item.id === id); - const useCase = getFirstUseCaseOfFeatureConfigs(workspaceObj?.features || []); - if (useCase && navGroups) { - // should be workspace use case overview page - const availableLinks = navGroups[useCase].navLinks?.filter( - (navLink) => navLink.workspaceAvailability !== WorkspaceAvailability.outsideWorkspace - ); - const appId = availableLinks?.[0].id; - navigateToAppWithinWorkspace({ application, http }, id, appId); + if (application && http) { + navigateToWorkspaceDetail({ application, http }, id); } }; diff --git a/src/plugins/workspace/public/components/use_case_overview/get_started_cards.tsx b/src/plugins/workspace/public/components/use_case_overview/get_started_cards.tsx new file mode 100644 index 000000000000..f4edb5466215 --- /dev/null +++ b/src/plugins/workspace/public/components/use_case_overview/get_started_cards.tsx @@ -0,0 +1,73 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiI18n } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import React from 'react'; + +interface GetStartCard { + id: string; + title: string; + description: string; + footer: React.JSX.Element; + navigateAppId: string; + order: number; +} + +const DISCOVER_APP_ID = 'discover'; +const VISUALIZE_APP_ID = 'visualize'; +const DASHBOARDS_APP_ID = 'dashboards'; + +export const getStartedCards: GetStartCard[] = [ + { + id: 'get_start_discover', + title: i18n.translate('workspace.essential_overview.discover.card.title', { + defaultMessage: 'Discover insights', + }), + description: i18n.translate('workspace.essential_overview.discover.card.description', { + defaultMessage: 'Explore data interactively to uncover insights.', + }), + footer: ( + + ), + navigateAppId: DISCOVER_APP_ID, + order: 20, + }, + { + id: 'get_start_visualization', + title: i18n.translate('workspace.essential_overview.visualize.card.title', { + defaultMessage: 'Visualize data', + }), + description: i18n.translate('workspace.essential_overview.visualize.card.description', { + defaultMessage: + 'Unlock insightful data exploration with visualization and aggregation tools.', + }), + footer: ( + + ), + navigateAppId: VISUALIZE_APP_ID, + order: 30, + }, + { + id: 'get_start_dashboards', + title: i18n.translate('workspace.essential_overview.dashboards.card.title', { + defaultMessage: 'View the big picture', + }), + description: i18n.translate('workspace.essential_overview.dashboards.card.description', { + defaultMessage: 'Gain clarity and visibility with dynamic data visualization tools.', + }), + footer: ( + + ), + navigateAppId: DASHBOARDS_APP_ID, + order: 40, + }, +]; diff --git a/src/plugins/workspace/public/components/use_case_overview/index.ts b/src/plugins/workspace/public/components/use_case_overview/index.ts new file mode 100644 index 000000000000..9691737d216d --- /dev/null +++ b/src/plugins/workspace/public/components/use_case_overview/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { setEssentialOverviewSection, registerEssentialOverviewContent } from './setup_overview'; diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx new file mode 100644 index 000000000000..16155d499744 --- /dev/null +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx @@ -0,0 +1,122 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { CoreStart } from 'opensearch-dashboards/public'; +import { + ContentManagementPluginSetup, + ContentManagementPluginStart, +} from '../../../../content_management/public'; +import { + ESSENTIAL_OVERVIEW_CONTENT_AREAS, + ESSENTIAL_OVERVIEW_PAGE_ID, + SECTIONS, +} from '../../../common/constants'; +import { getStartedCards } from './get_started_cards'; +import { + HomeListCard, + LEARN_OPENSEARCH_CONFIG, + WHATS_NEW_CONFIG, +} from '../../../../../plugins/home/public'; + +// Essential overview part +export const setEssentialOverviewSection = (contentManagement: ContentManagementPluginSetup) => { + contentManagement.registerPage({ + id: ESSENTIAL_OVERVIEW_PAGE_ID, + title: 'Overview', + sections: [ + { + id: SECTIONS.SERVICE_CARDS, + order: 3000, + kind: 'dashboard', + }, + { + id: SECTIONS.RECENTLY_VIEWED, + order: 2000, + title: 'Recently viewed', + kind: 'custom', + render: (contents) => { + return ( + <> + {contents.map((content) => { + if (content.kind === 'custom') { + return content.render(); + } + + return null; + })} + + ); + }, + }, + { + id: SECTIONS.GET_STARTED, + order: 1000, + kind: 'card', + }, + ], + }); +}; + +export const registerEssentialOverviewContent = ( + contentManagement: ContentManagementPluginStart, + core: CoreStart +) => { + getStartedCards.forEach((card) => { + contentManagement.registerContentProvider({ + id: card.id, + getTargetArea: () => ESSENTIAL_OVERVIEW_CONTENT_AREAS.GET_STARTED, + getContent: () => ({ + id: card.id, + kind: 'card', + order: card.order, + description: card.description, + title: card.title, + selectable: { + onClick: () => { + core.application.navigateToApp(card.navigateAppId); + }, + children: card.footer, + isSelected: false, + }, + }), + }); + }); + + // card + contentManagement.registerContentProvider({ + id: 'whats_new_cards_essential_overview', + getContent: () => ({ + id: 'whats_new', + kind: 'custom', + order: 10, + width: 24, + render: () => + React.createElement(HomeListCard, { + config: WHATS_NEW_CONFIG, + }), + }), + getTargetArea: () => ESSENTIAL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + }); + + contentManagement.registerContentProvider({ + id: 'learn_opensearch_cards_essential_overview', + getContent: () => ({ + id: 'learn_opensearch', + kind: 'custom', + order: 20, + width: 24, + render: () => + React.createElement(HomeListCard, { + config: LEARN_OPENSEARCH_CONFIG, + }), + }), + getTargetArea: () => ESSENTIAL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + }); +}; diff --git a/src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx b/src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx new file mode 100644 index 000000000000..e8e7f45eda81 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx @@ -0,0 +1,25 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { I18nProvider } from '@osd/i18n/react'; +import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; +import { Services } from '../types'; + +interface WorkspaceUseCaseOverviewProps { + pageId: string; +} + +export const WorkspaceUseCaseOverviewApp = (props: WorkspaceUseCaseOverviewProps) => { + const { + services: { contentManagement }, + } = useOpenSearchDashboards(); + + const pageId = props.pageId; + + return ( + {contentManagement ? contentManagement.renderPage(pageId) : null} + ); +}; diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 77969fa9b44d..01f35adf72e9 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -31,13 +31,18 @@ import { WORKSPACE_LIST_APP_ID, WORKSPACE_USE_CASES, WORKSPACE_INITIAL_APP_ID, + ESSENTIAL_OVERVIEW_APP_ID, + ANALYTICS_OVERVIEW_CONTENT_AREAS, } from '../common/constants'; import { getWorkspaceIdFromUrl } from '../../../core/public/utils'; import { Services, WorkspaceUseCase } from './types'; import { WorkspaceClient } from './workspace_client'; import { SavedObjectsManagementPluginSetup } from '../../../plugins/saved_objects_management/public'; import { ManagementSetup } from '../../../plugins/management/public'; -import { ContentManagementPluginStart } from '../../../plugins/content_management/public'; +import { + ContentManagementPluginSetup, + ContentManagementPluginStart, +} from '../../../plugins/content_management/public'; import { WorkspaceMenu } from './components/workspace_menu/workspace_menu'; import { getWorkspaceColumn } from './components/workspace_column'; import { DataSourceManagementPluginSetup } from '../../../plugins/data_source_management/public'; @@ -53,8 +58,12 @@ import { toMountPoint } from '../../opensearch_dashboards_react/public'; import { UseCaseService } from './services/use_case_service'; import { WorkspaceListCard } from './components/service_card'; import { UseCaseFooter } from './components/home_get_start_card'; -import { HOME_CONTENT_AREAS } from '../../home/public'; import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; +import { HOME_CONTENT_AREAS } from '../../../plugins/home/public'; +import { + registerEssentialOverviewContent, + setEssentialOverviewSection, +} from './components/use_case_overview'; type WorkspaceAppType = ( params: AppMountParameters, @@ -66,6 +75,7 @@ interface WorkspacePluginSetupDeps { savedObjectsManagement?: SavedObjectsManagementPluginSetup; management?: ManagementSetup; dataSourceManagement?: DataSourceManagementPluginSetup; + contentManagement?: ContentManagementPluginSetup; } export interface WorkspacePluginStartDeps { @@ -239,7 +249,12 @@ export class WorkspacePlugin public async setup( core: CoreSetup, - { savedObjectsManagement, management, dataSourceManagement }: WorkspacePluginSetupDeps + { + savedObjectsManagement, + management, + dataSourceManagement, + contentManagement, + }: WorkspacePluginSetupDeps ) { const workspaceClient = new WorkspaceClient(core.http, core.workspaces); await workspaceClient.init(); @@ -406,6 +421,43 @@ export class WorkspacePlugin }, ]); + if (core.chrome.navGroup.getNavGroupEnabled() && contentManagement) { + // workspace essential use case overview + core.application.register({ + id: ESSENTIAL_OVERVIEW_APP_ID, + title: '', + async mount(params: AppMountParameters) { + const { renderOverviewApp } = await import('./application'); + const [ + coreStart, + { contentManagement: contentManagementStart }, + ] = await core.getStartServices(); + const services = { + ...coreStart, + workspaceClient, + dataSourceManagement, + contentManagement: contentManagementStart, + }; + + return renderOverviewApp(params, services, ESSENTIAL_OVERVIEW_APP_ID); + }, + workspaceAvailability: WorkspaceAvailability.insideWorkspace, + }); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.essentials, [ + { + id: ESSENTIAL_OVERVIEW_APP_ID, + order: -1, + title: i18n.translate('workspace.nav.essential_overview.title', { + defaultMessage: 'Overview', + }), + }, + ]); + + // initial the page structure + setEssentialOverviewSection(contentManagement); + } + /** * register workspace column into saved objects table */ @@ -441,7 +493,10 @@ export class WorkspacePlugin useCases.forEach((useCase, index) => { contentManagement.registerContentProvider({ id: `home_get_start_${useCase.id}`, - getTargetArea: () => HOME_CONTENT_AREAS.GET_STARTED, + getTargetArea: () => [ + HOME_CONTENT_AREAS.GET_STARTED, + ANALYTICS_OVERVIEW_CONTENT_AREAS.GET_STARTED, + ], getContent: () => ({ id: useCase.id, kind: 'card', @@ -503,6 +558,9 @@ export class WorkspacePlugin // set breadcrumbs enricher for workspace this.breadcrumbsSubscription = enrichBreadcrumbsWithWorkspace(core); + + // register content to essential overview page + registerEssentialOverviewContent(contentManagement, core); } return {}; } diff --git a/src/plugins/workspace/public/types.ts b/src/plugins/workspace/public/types.ts index d5cfc224416f..360ea26b2609 100644 --- a/src/plugins/workspace/public/types.ts +++ b/src/plugins/workspace/public/types.ts @@ -7,11 +7,13 @@ import { CoreStart } from '../../../core/public'; import { WorkspaceClient } from './workspace_client'; import { DataSourceManagementPluginSetup } from '../../../plugins/data_source_management/public'; import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; +import { ContentManagementPluginStart } from '../../../plugins/content_management/public'; export type Services = CoreStart & { workspaceClient: WorkspaceClient; dataSourceManagement?: DataSourceManagementPluginSetup; navigationUI?: NavigationPublicPluginStart['ui']; + contentManagement?: ContentManagementPluginStart; }; export interface WorkspaceUseCase { From e166b502b5897413166de33651dd557d413bbc11 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Sat, 17 Aug 2024 23:18:46 +0800 Subject: [PATCH 03/20] set breadcrumb for overview page Signed-off-by: Hailong Cui --- src/plugins/workspace/public/application.tsx | 3 ++- .../workspace_detail/workspace_detail_panel.tsx | 8 ++++++-- .../workspace_use_case_overview_app.tsx | 17 +++++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/plugins/workspace/public/application.tsx b/src/plugins/workspace/public/application.tsx index c975323d0fa2..cc9e41888ba2 100644 --- a/src/plugins/workspace/public/application.tsx +++ b/src/plugins/workspace/public/application.tsx @@ -16,6 +16,7 @@ import { WorkspaceCreatorProps } from './components/workspace_creator/workspace_ import { WorkspaceDetailApp } from './components/workspace_detail_app'; import { WorkspaceDetailProps } from './components/workspace_detail/workspace_detail'; import { WorkspaceInitialApp } from './components/workspace_initial_app'; +import { WorkspaceUseCaseOverviewApp } from './components/workspace_use_case_overview_app'; export const renderCreatorApp = ( { element }: AppMountParameters, @@ -110,7 +111,7 @@ export const renderOverviewApp = async ( ) => { ReactDOM.render( - {services.contentManagement?.renderPage(pageId)} + , element ); diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx index 1f426743ac17..81f50b568887 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx @@ -45,8 +45,12 @@ const overview = i18n.translate('workspace.detail.overview', { }); function getOwners(currentWorkspace: WorkspaceAttributeWithPermission) { - const { groups = [], users = [] } = currentWorkspace.permissions!.write; - return [...groups, ...users]; + if (currentWorkspace.permissions) { + const { groups = [], users = [] } = currentWorkspace.permissions.write; + return [...groups, ...users]; + } else { + return []; + } } interface WorkspaceDetailPanelProps { diff --git a/src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx b/src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx index e8e7f45eda81..dcdcee22b729 100644 --- a/src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx +++ b/src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx @@ -3,8 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React from 'react'; +import React, { useEffect } from 'react'; import { I18nProvider } from '@osd/i18n/react'; +import { useObservable } from 'react-use'; +import { EuiBreadcrumb } from '@elastic/eui'; import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; import { Services } from '../types'; @@ -14,9 +16,20 @@ interface WorkspaceUseCaseOverviewProps { export const WorkspaceUseCaseOverviewApp = (props: WorkspaceUseCaseOverviewProps) => { const { - services: { contentManagement }, + services: { contentManagement, workspaces, chrome }, } = useOpenSearchDashboards(); + const currentWorkspace = useObservable(workspaces.currentWorkspace$); + + useEffect(() => { + const breadcrumbs: EuiBreadcrumb[] = [ + { + text: currentWorkspace?.name, + }, + ]; + chrome.setBreadcrumbs(breadcrumbs); + }, [chrome, currentWorkspace]); + const pageId = props.pageId; return ( From dcd72ef4ab0f51f518018f8256bac92f9f933116 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Tue, 20 Aug 2024 11:45:39 +0800 Subject: [PATCH 04/20] remove width Signed-off-by: Hailong Cui --- .../public/services/content_management/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/content_management/public/services/content_management/types.ts b/src/plugins/content_management/public/services/content_management/types.ts index a073f6ef3f85..aab24ab7c916 100644 --- a/src/plugins/content_management/public/services/content_management/types.ts +++ b/src/plugins/content_management/public/services/content_management/types.ts @@ -52,7 +52,6 @@ export type Content = id: string; order: number; input: SavedObjectInput; - width: number; } | { kind: 'custom'; From d951e7323bd2b3acf7033574805004034775b33c Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Tue, 20 Aug 2024 16:05:32 +0800 Subject: [PATCH 05/20] Analytics use case overview Signed-off-by: Hailong Cui --- .../saved_objects_management/public/plugin.ts | 2 +- src/plugins/workspace/common/constants.ts | 10 +- src/plugins/workspace/public/application.tsx | 2 +- .../use_case_overview/setup_overview.tsx | 108 ++++++++++++++++++ src/plugins/workspace/public/plugin.ts | 53 +++++++-- 5 files changed, 161 insertions(+), 14 deletions(-) diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts index bcbd55207cac..ef1417ef8b65 100644 --- a/src/plugins/saved_objects_management/public/plugin.ts +++ b/src/plugins/saved_objects_management/public/plugin.ts @@ -239,7 +239,7 @@ export class SavedObjectsManagementPlugin getTargetArea: () => [ HOME_CONTENT_AREAS.RECENTLY_VIEWED, 'essential_overview/recently_viewed', - 'analytics_overview/recently_viewed', + 'analytics_all_overview/recently_viewed', ], }); diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index 60812ee79401..25b1eb4f4458 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -192,7 +192,7 @@ export const CURRENT_USER_PLACEHOLDER = '%me%'; export const MAX_WORKSPACE_NAME_LENGTH = 40; export const MAX_WORKSPACE_DESCRIPTION_LENGTH = 200; export const ESSENTIAL_OVERVIEW_PAGE_ID = 'essential_overview'; -export const ANALYTICS_OVERVIEW_PAGE_ID = 'analytics_overview'; +export const ANALYTICS_ALL_OVERVIEW_PAGE_ID = 'analytics_all_overview'; export enum SECTIONS { GET_STARTED = `get_started`, SERVICE_CARDS = `service_cards`, @@ -205,8 +205,8 @@ export enum ESSENTIAL_OVERVIEW_CONTENT_AREAS { RECENTLY_VIEWED = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, } -export enum ANALYTICS_OVERVIEW_CONTENT_AREAS { - GET_STARTED = `${ANALYTICS_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, - SERVICE_CARDS = `${ANALYTICS_OVERVIEW_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, - RECENTLY_VIEWED = `${ANALYTICS_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, +export enum ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS { + GET_STARTED = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, + SERVICE_CARDS = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, + RECENTLY_VIEWED = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, } diff --git a/src/plugins/workspace/public/application.tsx b/src/plugins/workspace/public/application.tsx index cc9e41888ba2..88a7825b6883 100644 --- a/src/plugins/workspace/public/application.tsx +++ b/src/plugins/workspace/public/application.tsx @@ -104,7 +104,7 @@ export const renderInitialApp = ({}: AppMountParameters, services: Services) => }; }; -export const renderOverviewApp = async ( +export const renderUseCaseOverviewApp = async ( { element }: AppMountParameters, services: Services, pageId: string diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx index 16155d499744..ae272c8275e6 100644 --- a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx @@ -9,11 +9,15 @@ import React from 'react'; import { CoreStart } from 'opensearch-dashboards/public'; +import { EuiIcon } from '@elastic/eui'; +import { first } from 'rxjs/operators'; import { ContentManagementPluginSetup, ContentManagementPluginStart, } from '../../../../content_management/public'; import { + ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS, + ANALYTICS_ALL_OVERVIEW_PAGE_ID, ESSENTIAL_OVERVIEW_CONTENT_AREAS, ESSENTIAL_OVERVIEW_PAGE_ID, SECTIONS, @@ -24,6 +28,7 @@ import { LEARN_OPENSEARCH_CONFIG, WHATS_NEW_CONFIG, } from '../../../../../plugins/home/public'; +import { DEFAULT_NAV_GROUPS } from '../../../../../core/public'; // Essential overview part export const setEssentialOverviewSection = (contentManagement: ContentManagementPluginSetup) => { @@ -120,3 +125,106 @@ export const registerEssentialOverviewContent = ( getTargetArea: () => ESSENTIAL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, }); }; + +// Analytics(All) overview part +export const setAnalyticsAllOverviewSection = (contentManagement: ContentManagementPluginSetup) => { + contentManagement.registerPage({ + id: ANALYTICS_ALL_OVERVIEW_PAGE_ID, + title: 'Overview', + sections: [ + { + id: SECTIONS.SERVICE_CARDS, + order: 3000, + kind: 'dashboard', + }, + { + id: SECTIONS.RECENTLY_VIEWED, + order: 2000, + title: 'Recently viewed', + kind: 'custom', + render: (contents) => { + return ( + <> + {contents.map((content) => { + if (content.kind === 'custom') { + return content.render(); + } + + return null; + })} + + ); + }, + }, + { + id: SECTIONS.GET_STARTED, + order: 1000, + kind: 'card', + }, + ], + }); +}; + +export const registerAnalyticsAllOverviewContent = ( + contentManagement: ContentManagementPluginStart, + core: CoreStart +) => { + const useCaseCards = [ + DEFAULT_NAV_GROUPS.observability, + DEFAULT_NAV_GROUPS['security-analytics'], + DEFAULT_NAV_GROUPS.search, + ]; + useCaseCards.forEach((card, index) => { + contentManagement.registerContentProvider({ + id: card.id, + getTargetArea: () => ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.GET_STARTED, + getContent: () => ({ + id: card.id, + kind: 'card', + getIcon: () => React.createElement(EuiIcon, { size: 'xl', type: 'spacesApp' }), + order: card.order || index, + description: card.description, + title: card.title, + onClick: async () => { + const navGroups = await core.chrome.navGroup.getNavGroupsMap$().pipe(first()).toPromise(); + const group = navGroups[card.id]; + if (group) { + const appId = group.navLinks?.[0].id; + if (appId) core.application.navigateToApp(appId); + } + }, + }), + }); + }); + + // card + contentManagement.registerContentProvider({ + id: 'whats_new_cards_essential_overview', + getContent: () => ({ + id: 'whats_new', + kind: 'custom', + order: 30, + width: 12, + render: () => + React.createElement(HomeListCard, { + config: WHATS_NEW_CONFIG, + }), + }), + getTargetArea: () => ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + }); + + contentManagement.registerContentProvider({ + id: 'learn_opensearch_cards_essential_overview', + getContent: () => ({ + id: 'learn_opensearch', + kind: 'custom', + order: 40, + width: 12, + render: () => + React.createElement(HomeListCard, { + config: LEARN_OPENSEARCH_CONFIG, + }), + }), + getTargetArea: () => ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + }); +}; diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 01f35adf72e9..fae653c118c9 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -32,7 +32,7 @@ import { WORKSPACE_USE_CASES, WORKSPACE_INITIAL_APP_ID, ESSENTIAL_OVERVIEW_APP_ID, - ANALYTICS_OVERVIEW_CONTENT_AREAS, + ANALYTICS_OVERVIEW_ALL_APP_ID, } from '../common/constants'; import { getWorkspaceIdFromUrl } from '../../../core/public/utils'; import { Services, WorkspaceUseCase } from './types'; @@ -64,6 +64,10 @@ import { registerEssentialOverviewContent, setEssentialOverviewSection, } from './components/use_case_overview'; +import { + registerAnalyticsAllOverviewContent, + setAnalyticsAllOverviewSection, +} from './components/use_case_overview/setup_overview'; type WorkspaceAppType = ( params: AppMountParameters, @@ -427,7 +431,7 @@ export class WorkspacePlugin id: ESSENTIAL_OVERVIEW_APP_ID, title: '', async mount(params: AppMountParameters) { - const { renderOverviewApp } = await import('./application'); + const { renderUseCaseOverviewApp } = await import('./application'); const [ coreStart, { contentManagement: contentManagementStart }, @@ -439,7 +443,7 @@ export class WorkspacePlugin contentManagement: contentManagementStart, }; - return renderOverviewApp(params, services, ESSENTIAL_OVERVIEW_APP_ID); + return renderUseCaseOverviewApp(params, services, ESSENTIAL_OVERVIEW_APP_ID); }, workspaceAvailability: WorkspaceAvailability.insideWorkspace, }); @@ -456,6 +460,41 @@ export class WorkspacePlugin // initial the page structure setEssentialOverviewSection(contentManagement); + + // register workspace Analytics(all) use case overview app + core.application.register({ + id: ANALYTICS_OVERVIEW_ALL_APP_ID, + title: '', + async mount(params: AppMountParameters) { + const { renderUseCaseOverviewApp } = await import('./application'); + const [ + coreStart, + { contentManagement: contentManagementStart }, + ] = await core.getStartServices(); + const services = { + ...coreStart, + workspaceClient, + dataSourceManagement, + contentManagement: contentManagementStart, + }; + + return renderUseCaseOverviewApp(params, services, ANALYTICS_OVERVIEW_ALL_APP_ID); + }, + workspaceAvailability: WorkspaceAvailability.insideWorkspace, + }); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ + { + id: ANALYTICS_OVERVIEW_ALL_APP_ID, + order: -1, + title: i18n.translate('workspace.nav.analyticsAll_overview.title', { + defaultMessage: 'Overview', + }), + }, + ]); + + // initial the page structure + setAnalyticsAllOverviewSection(contentManagement); } /** @@ -493,10 +532,7 @@ export class WorkspacePlugin useCases.forEach((useCase, index) => { contentManagement.registerContentProvider({ id: `home_get_start_${useCase.id}`, - getTargetArea: () => [ - HOME_CONTENT_AREAS.GET_STARTED, - ANALYTICS_OVERVIEW_CONTENT_AREAS.GET_STARTED, - ], + getTargetArea: () => [HOME_CONTENT_AREAS.GET_STARTED], getContent: () => ({ id: useCase.id, kind: 'card', @@ -561,6 +597,9 @@ export class WorkspacePlugin // register content to essential overview page registerEssentialOverviewContent(contentManagement, core); + + // register content to analytics(All) overview page + registerAnalyticsAllOverviewContent(contentManagement, core); } return {}; } From ca271ff22cae978bd040d29829e2f2529f93ab98 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Tue, 20 Aug 2024 17:32:37 +0800 Subject: [PATCH 06/20] add unit test Signed-off-by: Hailong Cui --- .../card_container/card_embeddable.test.tsx | 29 ++++ .../content_management_service.test.ts | 23 +++ .../sample_data/sample_data_card.test.tsx | 42 +++++ .../use_case_overview/setup_overview.test.tsx | 147 ++++++++++++++++++ src/plugins/workspace/public/plugin.test.ts | 80 ++++++++++ 5 files changed, 321 insertions(+) create mode 100644 src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx create mode 100644 src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx b/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx index a87cd43554ea..d249b6772b50 100644 --- a/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx +++ b/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx @@ -28,3 +28,32 @@ test('CardEmbeddable should render a card with the title', () => { Array.from(node.querySelectorAll('*')).find((ele) => ele.textContent?.trim() === 'card title') ).toBeFalsy(); }); + +test('CardEmbeddable should render a card with the selectable', () => { + const embeddable = new CardEmbeddable({ + id: 'card-id', + title: 'card title', + description: '', + selectable: { + children: 'selectable line', + onSelect: () => {}, + }, + }); + + const node = document.createElement('div'); + embeddable.render(node); + + // it should render the card with title specified + expect( + Array.from(node.querySelectorAll('*')).find( + (ele) => ele.textContent?.trim() === 'selectable line' + ) + ).toBeTruthy(); + + embeddable.destroy(); + expect( + Array.from(node.querySelectorAll('*')).find( + (ele) => ele.textContent?.trim() === 'selectable line' + ) + ).toBeFalsy(); +}); diff --git a/src/plugins/content_management/public/services/content_management/content_management_service.test.ts b/src/plugins/content_management/public/services/content_management/content_management_service.test.ts index b68157838b09..442b608513bb 100644 --- a/src/plugins/content_management/public/services/content_management/content_management_service.test.ts +++ b/src/plugins/content_management/public/services/content_management/content_management_service.test.ts @@ -47,6 +47,29 @@ test('it register content provider', () => { expect(cms.getPage('page1')?.getContents('section1')).toHaveLength(1); }); +test('it register content provider to multiple destination', () => { + const cms = new ContentManagementService(); + cms.registerPage({ id: 'page1', sections: [{ id: 'section1', kind: 'card', order: 0 }] }); + cms.registerPage({ id: 'page2', sections: [{ id: 'section1', kind: 'card', order: 0 }] }); + cms.registerContentProvider({ + id: 'content_provider1', + getTargetArea() { + return ['page1/section1', 'page2/section1']; + }, + getContent() { + return { + kind: 'card', + id: 'content1', + title: 'card', + description: 'descriptions', + order: 0, + }; + }, + }); + expect(cms.getPage('page1')?.getContents('section1')).toHaveLength(1); + expect(cms.getPage('page2')?.getContents('section1')).toHaveLength(1); +}); + test('it should throw error when register content provider with invalid target area', () => { const cms = new ContentManagementService(); cms.registerPage({ id: 'page1', sections: [{ id: 'section1', kind: 'card', order: 0 }] }); diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx new file mode 100644 index 000000000000..89a57173ee65 --- /dev/null +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx @@ -0,0 +1,42 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { registerSampleDataCard } from './sample_data_card'; +import { ContentManagementPluginStart } from '../../../../../../plugins/content_management/public'; +import { coreMock } from '../../../../../../core/public/mocks'; + +describe('Sample data card', () => { + const coreStart = coreMock.createStart(); + const registerContentProviderMock = jest.fn(); + + const contentManagement: ContentManagementPluginStart = { + registerContentProvider: registerContentProviderMock, + renderPage: jest.fn(), + updatePageSection: jest.fn(), + }; + + it('should call the getTargetArea function with the correct arguments', () => { + registerSampleDataCard(contentManagement, coreStart); + const call = registerContentProviderMock.mock.calls[0]; + expect(call[0].getTargetArea()).toEqual(['essential_overview/get_started']); + expect(call[0].getContent()).toMatchInlineSnapshot(` + Object { + "description": "Explore sample data before adding your own.", + "id": "sample_data", + "kind": "card", + "order": 0, + "selectable": Object { + "children": , + "isSelected": false, + "onClick": [Function], + }, + "title": "Try openSearch", + } + `); + }); +}); diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx new file mode 100644 index 000000000000..84f5a27712d6 --- /dev/null +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx @@ -0,0 +1,147 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + ContentManagementPluginSetup, + ContentManagementPluginStart, +} from '../../../../../plugins/content_management/public'; +import { coreMock } from '../../../../../core/public/mocks'; +import { + registerAnalyticsAllOverviewContent, + registerEssentialOverviewContent, + setEssentialOverviewSection, +} from './setup_overview'; + +describe('Setup use case overview', () => { + const coreStart = coreMock.createStart(); + const registerContentProviderMock = jest.fn(); + + const contentManagementStartMock: ContentManagementPluginStart = { + registerContentProvider: registerContentProviderMock, + renderPage: jest.fn(), + updatePageSection: jest.fn(), + }; + + const registerPageMock = jest.fn(); + const contentManagementSetupMock: ContentManagementPluginSetup = { + registerPage: registerPageMock, + }; + + beforeEach(() => { + registerContentProviderMock.mockClear(); + }); + + it('setEssentialOverviewSection', () => { + setEssentialOverviewSection(contentManagementSetupMock); + + const call = registerPageMock.mock.calls[0]; + expect(call[0]).toMatchInlineSnapshot(` + Object { + "id": "essential_overview", + "sections": Array [ + Object { + "id": "service_cards", + "kind": "dashboard", + "order": 3000, + }, + Object { + "id": "recently_viewed", + "kind": "custom", + "order": 2000, + "render": [Function], + "title": "Recently viewed", + }, + Object { + "id": "get_started", + "kind": "card", + "order": 1000, + }, + ], + "title": "Overview", + } + `); + }); + + it('registerEssentialOverviewContent', () => { + registerEssentialOverviewContent(contentManagementStartMock, coreStart); + + const calls = registerContentProviderMock.mock.calls; + expect(calls.length).toBe(5); + + const firstCall = calls[0]; + expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot(`"essential_overview/get_started"`); + expect(firstCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "description": "Explore data interactively to uncover insights.", + "id": "get_start_discover", + "kind": "card", + "order": 20, + "selectable": Object { + "children": , + "isSelected": false, + "onClick": [Function], + }, + "title": "Discover insights", + } + `); + }); + + it('setAnalyticsAllOverviewSection', () => { + setEssentialOverviewSection(contentManagementSetupMock); + + const call = registerPageMock.mock.calls[0]; + expect(call[0]).toMatchInlineSnapshot(` + Object { + "id": "essential_overview", + "sections": Array [ + Object { + "id": "service_cards", + "kind": "dashboard", + "order": 3000, + }, + Object { + "id": "recently_viewed", + "kind": "custom", + "order": 2000, + "render": [Function], + "title": "Recently viewed", + }, + Object { + "id": "get_started", + "kind": "card", + "order": 1000, + }, + ], + "title": "Overview", + } + `); + }); + + it('registerAnalyticsAllOverviewContent', () => { + registerAnalyticsAllOverviewContent(contentManagementStartMock, coreStart); + + const calls = registerContentProviderMock.mock.calls; + expect(calls.length).toBe(5); + + const firstCall = calls[0]; + expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot( + `"analytics_all_overview/get_started"` + ); + expect(firstCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "description": "Gain visibility into system health, performance, and reliability through monitoring and analysis of logs, metrics, and traces.", + "getIcon": [Function], + "id": "observability", + "kind": "card", + "onClick": [Function], + "order": 4000, + "title": "Observability", + } + `); + }); +}); diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index 41f779911876..40860b406947 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -215,6 +215,86 @@ describe('Workspace plugin', () => { ); }); + it('#setup should register workspace essential use case when new home is disabled', async () => { + const setupMock = { + ...coreMock.createSetup(), + chrome: { + ...coreMock.createSetup().chrome, + navGroup: { + ...coreMock.createSetup().chrome.navGroup, + getNavGroupEnabled: jest.fn().mockReturnValue(false), + }, + }, + }; + const workspacePlugin = new WorkspacePlugin(); + await workspacePlugin.setup(setupMock, { + contentManagement: { + registerPage: jest.fn(), + }, + }); + + expect(setupMock.application.register).not.toHaveBeenCalledWith( + expect.objectContaining({ + id: 'essential_overview', + }) + ); + expect(setupMock.application.register).not.toHaveBeenCalledWith( + expect.objectContaining({ + id: 'analytics_all_overview', + }) + ); + }); + + it('#setup should register workspace essential use case when new nav is enabled', async () => { + const setupMock = { + ...coreMock.createSetup(), + chrome: { + ...coreMock.createSetup().chrome, + navGroup: { + ...coreMock.createSetup().chrome.navGroup, + getNavGroupEnabled: jest.fn().mockReturnValue(true), + }, + }, + }; + const workspacePlugin = new WorkspacePlugin(); + await workspacePlugin.setup(setupMock, { + contentManagement: { + registerPage: jest.fn(), + }, + }); + + expect(setupMock.application.register).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'essential_overview', + }) + ); + }); + + it('#setup should register workspace analytics(All) use case when new nav is enabled', async () => { + const setupMock = { + ...coreMock.createSetup(), + chrome: { + ...coreMock.createSetup().chrome, + navGroup: { + ...coreMock.createSetup().chrome.navGroup, + getNavGroupEnabled: jest.fn().mockReturnValue(true), + }, + }, + }; + const workspacePlugin = new WorkspacePlugin(); + await workspacePlugin.setup(setupMock, { + contentManagement: { + registerPage: jest.fn(), + }, + }); + + expect(setupMock.application.register).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'analytics_all_overview', + }) + ); + }); + it('#start add workspace detail page to breadcrumbs when start', async () => { const startMock = coreMock.createStart(); const workspaceObject = { From a427120a334c32c93bb5720977335ff29b4bc5a4 Mon Sep 17 00:00:00 2001 From: "opensearch-changeset-bot[bot]" <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Date: Tue, 20 Aug 2024 09:35:18 +0000 Subject: [PATCH 07/20] Changeset file for PR #7673 created/updated --- changelogs/fragments/7673.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/fragments/7673.yml b/changelogs/fragments/7673.yml index 2bbd360048a4..f0a84647bad2 100644 --- a/changelogs/fragments/7673.yml +++ b/changelogs/fragments/7673.yml @@ -1,2 +1,2 @@ feat: -- [Workspace]Essential use case overview page ([#7673](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7673)) \ No newline at end of file +- [Workspace]Essential/Analytics(All) use case overview page ([#7673](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7673)) \ No newline at end of file From e2278637b9162e2a3931cabd2098d2d1b9a6323e Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Wed, 21 Aug 2024 15:25:43 +0800 Subject: [PATCH 08/20] add cardProps for card input Signed-off-by: Hailong Cui --- .../card_container/card_embeddable.test.tsx | 10 +++--- .../card_container/card_embeddable.tsx | 32 ++++++++++--------- .../public/components/card_container/types.ts | 4 +-- .../public/components/section_input.ts | 2 +- .../services/content_management/types.ts | 4 +-- .../sample_data/sample_data_card.test.tsx | 18 ++++++----- .../sample_data/sample_data_card.tsx | 14 ++++---- .../use_case_overview/setup_overview.test.tsx | 18 ++++++----- .../use_case_overview/setup_overview.tsx | 15 ++++++--- 9 files changed, 66 insertions(+), 51 deletions(-) diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx b/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx index d249b6772b50..4a8c7a7a8f4c 100644 --- a/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx +++ b/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx @@ -29,14 +29,16 @@ test('CardEmbeddable should render a card with the title', () => { ).toBeFalsy(); }); -test('CardEmbeddable should render a card with the selectable', () => { +test('CardEmbeddable should render a card with the cardProps', () => { const embeddable = new CardEmbeddable({ id: 'card-id', title: 'card title', description: '', - selectable: { - children: 'selectable line', - onSelect: () => {}, + cardProps: { + selectable: { + children: 'selectable line', + onSelect: () => {}, + }, }, }); diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable.tsx b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx index 914fb91b76e7..66532e508bed 100644 --- a/src/plugins/content_management/public/components/card_container/card_embeddable.tsx +++ b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx @@ -5,9 +5,8 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { EuiCard } from '@elastic/eui'; +import { EuiCard, EuiCardProps } from '@elastic/eui'; -import { EuiCardSelectProps } from '@elastic/eui/src/components/card/card_select'; import { Embeddable, EmbeddableInput, IContainer } from '../../../../embeddable/public'; export const CARD_EMBEDDABLE = 'card_embeddable'; @@ -16,7 +15,7 @@ export type CardEmbeddableInput = EmbeddableInput & { onClick?: () => void; getIcon?: () => React.ReactElement; getFooter?: () => React.ReactElement; - selectable?: EuiCardSelectProps; + cardProps?: Omit; }; export class CardEmbeddable extends Embeddable { @@ -32,18 +31,21 @@ export class CardEmbeddable extends Embeddable { ReactDOM.unmountComponentAtNode(this.node); } this.node = node; - ReactDOM.render( - , - node - ); + + const cardProps: EuiCardProps = { + ...(this.input.cardProps ? { ...this.input.cardProps } : {}), + title: this.input.title ?? '', + description: this.input.description, + onClick: this.input.onClick, + icon: this.input?.getIcon?.(), + }; + + if (!cardProps.layout || cardProps.layout === 'vertical') { + cardProps.textAlign = 'left'; + cardProps.footer = this.input?.getFooter?.(); + } + + ReactDOM.render(, node); } public destroy() { diff --git a/src/plugins/content_management/public/components/card_container/types.ts b/src/plugins/content_management/public/components/card_container/types.ts index 7f65f89c9946..4ddaf132ca93 100644 --- a/src/plugins/content_management/public/components/card_container/types.ts +++ b/src/plugins/content_management/public/components/card_container/types.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiCardSelectProps } from '@elastic/eui/src/components/card/card_select'; +import { EuiCardProps } from '@elastic/eui'; import { ContainerInput } from '../../../../embeddable/public'; export interface CardExplicitInput { @@ -12,7 +12,7 @@ export interface CardExplicitInput { onClick?: () => void; getIcon?: () => React.ReactElement; getFooter?: () => React.ReactElement; - selectable?: EuiCardSelectProps; + cardProps?: Omit; } export type CardContainerInput = ContainerInput & { diff --git a/src/plugins/content_management/public/components/section_input.ts b/src/plugins/content_management/public/components/section_input.ts index 1ed21decc5ef..3ae47b84881d 100644 --- a/src/plugins/content_management/public/components/section_input.ts +++ b/src/plugins/content_management/public/components/section_input.ts @@ -49,7 +49,7 @@ export const createCardInput = ( onClick: content.onClick, getIcon: content?.getIcon, getFooter: content?.getFooter, - selectable: content.selectable, + cardProps: content.cardProps, }, }; } diff --git a/src/plugins/content_management/public/services/content_management/types.ts b/src/plugins/content_management/public/services/content_management/types.ts index 2608ce35d572..11253b1138e2 100644 --- a/src/plugins/content_management/public/services/content_management/types.ts +++ b/src/plugins/content_management/public/services/content_management/types.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiCardSelectProps } from '@elastic/eui/src/components/card/card_select'; +import { EuiCardProps } from '@elastic/eui'; import { CardContainerExplicitInput } from '../../components/card_container/types'; import { DashboardContainerExplicitInput } from '../../components/types'; @@ -75,7 +75,7 @@ export type Content = onClick?: () => void; getIcon?: () => React.ReactElement; getFooter?: () => React.ReactElement; - selectable?: EuiCardSelectProps; + cardProps?: Omit; }; export type SavedObjectInput = diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx index 89a57173ee65..50ac28e1e815 100644 --- a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx @@ -23,18 +23,20 @@ describe('Sample data card', () => { expect(call[0].getTargetArea()).toEqual(['essential_overview/get_started']); expect(call[0].getContent()).toMatchInlineSnapshot(` Object { + "cardProps": Object { + "selectable": Object { + "children": , + "isSelected": false, + "onClick": [Function], + }, + }, "description": "Explore sample data before adding your own.", "id": "sample_data", "kind": "card", "order": 0, - "selectable": Object { - "children": , - "isSelected": false, - "onClick": [Function], - }, "title": "Try openSearch", } `); diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx index 42fa82b2f84e..c8ea197f39fb 100644 --- a/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx @@ -27,12 +27,14 @@ export const registerSampleDataCard = ( title: i18n.translate('home.sampleData.card.title', { defaultMessage: 'Try openSearch', }), - selectable: { - children: , - isSelected: false, - onClick: () => { - // TODO change to a modal - core.application.navigateToApp(IMPORT_SAMPLE_DATA_APP_ID); + cardProps: { + selectable: { + children: , + isSelected: false, + onClick: () => { + // TODO change to a modal + core.application.navigateToApp(IMPORT_SAMPLE_DATA_APP_ID); + }, }, }, }), diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx index 84f5a27712d6..0327e38192ec 100644 --- a/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx @@ -74,18 +74,20 @@ describe('Setup use case overview', () => { expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot(`"essential_overview/get_started"`); expect(firstCall[0].getContent()).toMatchInlineSnapshot(` Object { + "cardProps": Object { + "selectable": Object { + "children": , + "isSelected": false, + "onClick": [Function], + }, + }, "description": "Explore data interactively to uncover insights.", "id": "get_start_discover", "kind": "card", "order": 20, - "selectable": Object { - "children": , - "isSelected": false, - "onClick": [Function], - }, "title": "Discover insights", } `); diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx index ae272c8275e6..c49c0c17d0b3 100644 --- a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx @@ -83,12 +83,14 @@ export const registerEssentialOverviewContent = ( order: card.order, description: card.description, title: card.title, - selectable: { - onClick: () => { - core.application.navigateToApp(card.navigateAppId); + cardProps: { + selectable: { + onClick: () => { + core.application.navigateToApp(card.navigateAppId); + }, + children: card.footer, + isSelected: false, }, - children: card.footer, - isSelected: false, }, }), }); @@ -185,6 +187,9 @@ export const registerAnalyticsAllOverviewContent = ( order: card.order || index, description: card.description, title: card.title, + cardProps: { + layout: 'horizontal', + }, onClick: async () => { const navGroups = await core.chrome.navGroup.getNavGroupsMap$().pipe(first()).toPromise(); const group = navGroups[card.id]; From c8d124e1efca715164b26bbdf0a90e9f7cd9da0c Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Wed, 21 Aug 2024 16:23:22 +0800 Subject: [PATCH 09/20] remove repeat license header Signed-off-by: Hailong Cui --- .../public/components/use_case_overview/setup_overview.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx index c49c0c17d0b3..5d4452384e20 100644 --- a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx @@ -2,10 +2,6 @@ * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ import React from 'react'; import { CoreStart } from 'opensearch-dashboards/public'; From c8b2ddbd8b23960b673cc5dce69340e9ce441fe8 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Wed, 21 Aug 2024 17:52:26 +0800 Subject: [PATCH 10/20] navigates to use case overvie page instead of workspace detail Signed-off-by: Hailong Cui --- src/plugins/home/public/plugin.ts | 1 + .../use_case_overview/setup_overview.test.tsx | 3 ++ src/plugins/workspace/public/plugin.test.ts | 5 ++-- src/plugins/workspace/public/plugin.ts | 30 +++++++++---------- src/plugins/workspace/public/utils.ts | 3 +- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index 68fcadf0eb0e..afa8dffd5e42 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -171,6 +171,7 @@ export class HomePublicPlugin { id: PLUGIN_ID, title: 'Home', + order: 0, }, ]); diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx index 0327e38192ec..fc75a9f1a3e1 100644 --- a/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx @@ -136,6 +136,9 @@ describe('Setup use case overview', () => { ); expect(firstCall[0].getContent()).toMatchInlineSnapshot(` Object { + "cardProps": Object { + "layout": "horizontal", + }, "description": "Gain visibility into system health, performance, and reliability through monitoring and analysis of logs, metrics, and traces.", "getIcon": [Function], "id": "observability", diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index 40860b406947..5b87b2521345 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -177,7 +177,7 @@ describe('Workspace plugin', () => { ); }); - it('#setup should register workspace detail with a visible application and register to all nav group', async () => { + it('#setup should register workspace detail with a hidden application and not register to all nav group', async () => { const setupMock = coreMock.createSetup(); setupMock.chrome.navGroup.getNavGroupEnabled.mockReturnValue(true); const workspacePlugin = new WorkspacePlugin(); @@ -190,7 +190,8 @@ describe('Workspace plugin', () => { }) ); - expect(setupMock.chrome.navGroup.addNavLinksToGroup).toHaveBeenCalledWith( + // not register to all nav group + expect(setupMock.chrome.navGroup.addNavLinksToGroup).not.toHaveBeenCalledWith( DEFAULT_NAV_GROUPS.all, expect.arrayContaining([ { diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index fae653c118c9..177c1b54dd06 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -125,17 +125,25 @@ export class WorkspacePlugin this.registeredUseCases$, ]).subscribe(([currentWorkspace, registeredUseCases]) => { if (currentWorkspace) { - const isAllUseCase = - getFirstUseCaseOfFeatureConfigs(currentWorkspace.features || []) === ALL_USE_CASE_ID; + const workspaceUseCase = getFirstUseCaseOfFeatureConfigs(currentWorkspace.features || []); + const isAllUseCase = workspaceUseCase === ALL_USE_CASE_ID; this.appUpdater$.next((app) => { - // When in all workspace, the home should be replaced by workspace detail page + // When in all workspace, the home should be replaced by workspace overview page if (app.id === 'home' && isAllUseCase) { return { navLinkStatus: AppNavLinkStatus.hidden }; } - // show the overview page in all use case - if (app.id === WORKSPACE_DETAIL_APP_ID && isAllUseCase) { - return { navLinkStatus: AppNavLinkStatus.visible }; + // disable essential overview page for workspace use case is not essential + if ( + app.id === ESSENTIAL_OVERVIEW_APP_ID && + workspaceUseCase !== WORKSPACE_USE_CASES.essentials.id + ) { + return { status: AppStatus.inaccessible }; + } + + // disable analytics(All) overview page for workspace use case is not analytics(All) + if (app.id === ANALYTICS_OVERVIEW_ALL_APP_ID && workspaceUseCase !== ALL_USE_CASE_ID) { + return { status: AppStatus.inaccessible }; } if (isAppAccessibleInWorkspace(app, currentWorkspace, registeredUseCases)) { @@ -415,16 +423,6 @@ export class WorkspacePlugin workspaceAvailability: WorkspaceAvailability.outsideWorkspace, }); - core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ - { - id: WORKSPACE_DETAIL_APP_ID, - order: 100, - title: i18n.translate('workspace.nav.workspaceDetail.title', { - defaultMessage: 'Overview', - }), - }, - ]); - if (core.chrome.navGroup.getNavGroupEnabled() && contentManagement) { // workspace essential use case overview core.application.register({ diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index d57cacde7684..4a2cd0cbc463 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -376,8 +376,7 @@ export const getUseCaseUrl = ( application: ApplicationStart, http: HttpSetup ): string => { - const appId = - (useCase?.id !== ALL_USE_CASE_ID && useCase?.features?.[0]) || WORKSPACE_DETAIL_APP_ID; + const appId = useCase?.features?.[0] || WORKSPACE_DETAIL_APP_ID; const useCaseURL = formatUrlWithWorkspaceId( application.getUrlForApp(appId, { absolute: false, From 2cda4910bd9ae4194653a0674af5c0c982f82596 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Wed, 21 Aug 2024 22:21:14 +0800 Subject: [PATCH 11/20] Update src/plugins/content_management/public/components/card_container/card_embeddable.tsx Co-authored-by: SuZhou-Joe Signed-off-by: Hailong Cui --- .../public/components/card_container/card_embeddable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable.tsx b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx index 66532e508bed..1631b9e13959 100644 --- a/src/plugins/content_management/public/components/card_container/card_embeddable.tsx +++ b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx @@ -33,7 +33,7 @@ export class CardEmbeddable extends Embeddable { this.node = node; const cardProps: EuiCardProps = { - ...(this.input.cardProps ? { ...this.input.cardProps } : {}), + ...this.input.cardProps, title: this.input.title ?? '', description: this.input.description, onClick: this.input.onClick, From 5b0dea7d5c68f316b15a87ca1dcb82b7783d2923 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Thu, 22 Aug 2024 00:29:14 +0800 Subject: [PATCH 12/20] update page id to match pattern usecaseId_overview Signed-off-by: Hailong Cui --- .../public/components/section_render.tsx | 4 +- .../content_management/public/index.ts | 1 + .../saved_objects_management/public/plugin.ts | 4 +- src/plugins/workspace/common/constants.ts | 46 +------------- .../use_case_overview/setup_overview.test.tsx | 62 +++++++++++++++++-- .../use_case_overview/setup_overview.tsx | 43 +++++-------- src/plugins/workspace/public/plugin.test.ts | 4 +- src/plugins/workspace/public/plugin.ts | 20 +++--- src/plugins/workspace/public/utils.ts | 16 ++++- 9 files changed, 106 insertions(+), 94 deletions(-) diff --git a/src/plugins/content_management/public/components/section_render.tsx b/src/plugins/content_management/public/components/section_render.tsx index 17da6d20b90c..457b07cb7822 100644 --- a/src/plugins/content_management/public/components/section_render.tsx +++ b/src/plugins/content_management/public/components/section_render.tsx @@ -42,8 +42,8 @@ const DashboardSection = ({ section, embeddable, contents$, savedObjectsClient } if (section.kind === 'dashboard' && factory && input) { // const input = createDashboardSection(section, contents ?? []); return ( - // to make dashboard section align with others add margin left -8px -
+ // to make dashboard section align with others add margin left and right -8px +
); diff --git a/src/plugins/content_management/public/index.ts b/src/plugins/content_management/public/index.ts index c453782a7a9b..4ecd28b3942a 100644 --- a/src/plugins/content_management/public/index.ts +++ b/src/plugins/content_management/public/index.ts @@ -13,3 +13,4 @@ export const plugin = (initializerContext: PluginInitializerContext) => export * from './components'; export * from './mocks'; +export * from './services/content_management'; diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts index ef1417ef8b65..11912203f1f2 100644 --- a/src/plugins/saved_objects_management/public/plugin.ts +++ b/src/plugins/saved_objects_management/public/plugin.ts @@ -238,8 +238,8 @@ export class SavedObjectsManagementPlugin }, getTargetArea: () => [ HOME_CONTENT_AREAS.RECENTLY_VIEWED, - 'essential_overview/recently_viewed', - 'analytics_all_overview/recently_viewed', + 'analytics_overview/recently_viewed', + 'all_overview/recently_viewed', ], }); diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index 25b1eb4f4458..fede6a8cc9ca 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -4,15 +4,12 @@ */ import { i18n } from '@osd/i18n'; -import { AppCategory } from '../../../core/types'; export const WORKSPACE_FATAL_ERROR_APP_ID = 'workspace_fatal_error'; export const WORKSPACE_CREATE_APP_ID = 'workspace_create'; export const WORKSPACE_LIST_APP_ID = 'workspace_list'; export const WORKSPACE_DETAIL_APP_ID = 'workspace_detail'; export const WORKSPACE_INITIAL_APP_ID = 'workspace_initial'; -export const ESSENTIAL_OVERVIEW_APP_ID = 'essential_overview'; -export const ANALYTICS_OVERVIEW_ALL_APP_ID = 'analytics_all_overview'; /** * Since every workspace always have overview and update page, these features will be selected by default * and can't be changed in the workspace form feature selector @@ -43,44 +40,6 @@ export const PRIORITY_FOR_WORKSPACE_UI_SETTINGS_WRAPPER = -2; export const PRIORITY_FOR_WORKSPACE_CONFLICT_CONTROL_WRAPPER = -1; export const PRIORITY_FOR_PERMISSION_CONTROL_WRAPPER = 0; -export const WORKSPACE_APP_CATEGORIES: Record = Object.freeze({ - // below categories are for workspace - getStarted: { - id: 'getStarted', - label: i18n.translate('core.ui.getStarted.label', { - defaultMessage: 'Get started', - }), - order: 10000, - }, - dashboardAndReport: { - id: 'dashboardReport', - label: i18n.translate('core.ui.dashboardReport.label', { - defaultMessage: 'Dashboard and report', - }), - order: 11000, - }, - investigate: { - id: 'investigate', - label: i18n.translate('core.ui.investigate.label', { - defaultMessage: 'Investigate', - }), - order: 12000, - }, - detect: { - id: 'detect', - label: i18n.translate('core.ui.detect.label', { - defaultMessage: 'Detect', - }), - order: 13000, - }, - searchSolution: { - id: 'searchSolution', - label: i18n.translate('core.ui.searchSolution.label', { - defaultMessage: 'Build search solution', - }), - order: 14000, - }, -}); /** * * This is a temp solution to store relationships between use cases and features. @@ -191,8 +150,9 @@ export const CURRENT_USER_PLACEHOLDER = '%me%'; export const MAX_WORKSPACE_NAME_LENGTH = 40; export const MAX_WORKSPACE_DESCRIPTION_LENGTH = 200; -export const ESSENTIAL_OVERVIEW_PAGE_ID = 'essential_overview'; -export const ANALYTICS_ALL_OVERVIEW_PAGE_ID = 'analytics_all_overview'; +// pattern for the page id is useCaseId_overview +export const ESSENTIAL_OVERVIEW_PAGE_ID = 'analytics_overview'; +export const ANALYTICS_ALL_OVERVIEW_PAGE_ID = 'all_overview'; export enum SECTIONS { GET_STARTED = `get_started`, SERVICE_CARDS = `service_cards`, diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx index fc75a9f1a3e1..f457a3638b36 100644 --- a/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx @@ -39,7 +39,7 @@ describe('Setup use case overview', () => { const call = registerPageMock.mock.calls[0]; expect(call[0]).toMatchInlineSnapshot(` Object { - "id": "essential_overview", + "id": "analytics_overview", "sections": Array [ Object { "id": "service_cards", @@ -71,7 +71,7 @@ describe('Setup use case overview', () => { expect(calls.length).toBe(5); const firstCall = calls[0]; - expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot(`"essential_overview/get_started"`); + expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot(`"analytics_overview/get_started"`); expect(firstCall[0].getContent()).toMatchInlineSnapshot(` Object { "cardProps": Object { @@ -91,6 +91,32 @@ describe('Setup use case overview', () => { "title": "Discover insights", } `); + + const whatsNew = calls[3]; + expect(whatsNew[0].getTargetArea()).toMatchInlineSnapshot(`"analytics_overview/service_cards"`); + expect(whatsNew[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "whats_new", + "kind": "custom", + "order": 10, + "render": [Function], + "width": 24, + } + `); + + const learnOpenSearch = calls[4]; + expect(learnOpenSearch[0].getTargetArea()).toMatchInlineSnapshot( + `"analytics_overview/service_cards"` + ); + expect(learnOpenSearch[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "learn_opensearch", + "kind": "custom", + "order": 20, + "render": [Function], + "width": 24, + } + `); }); it('setAnalyticsAllOverviewSection', () => { @@ -99,7 +125,7 @@ describe('Setup use case overview', () => { const call = registerPageMock.mock.calls[0]; expect(call[0]).toMatchInlineSnapshot(` Object { - "id": "essential_overview", + "id": "analytics_overview", "sections": Array [ Object { "id": "service_cards", @@ -131,9 +157,7 @@ describe('Setup use case overview', () => { expect(calls.length).toBe(5); const firstCall = calls[0]; - expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot( - `"analytics_all_overview/get_started"` - ); + expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot(`"all_overview/get_started"`); expect(firstCall[0].getContent()).toMatchInlineSnapshot(` Object { "cardProps": Object { @@ -148,5 +172,31 @@ describe('Setup use case overview', () => { "title": "Observability", } `); + + const whatsNew = calls[3]; + expect(whatsNew[0].getTargetArea()).toMatchInlineSnapshot(`"all_overview/service_cards"`); + expect(whatsNew[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "whats_new", + "kind": "custom", + "order": 30, + "render": [Function], + "width": 12, + } + `); + + const learnOpenSearch = calls[4]; + expect(learnOpenSearch[0].getTargetArea()).toMatchInlineSnapshot( + `"all_overview/service_cards"` + ); + expect(learnOpenSearch[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "learn_opensearch", + "kind": "custom", + "order": 40, + "render": [Function], + "width": 12, + } + `); }); }); diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx index 5d4452384e20..a1814c505a61 100644 --- a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx @@ -25,6 +25,21 @@ import { WHATS_NEW_CONFIG, } from '../../../../../plugins/home/public'; import { DEFAULT_NAV_GROUPS } from '../../../../../core/public'; +import { Content } from '../../../../../plugins/content_management/public'; + +const recentlyViewSectionRender = (contents: Content[]) => { + return ( + <> + {contents.map((content) => { + if (content.kind === 'custom') { + return content.render(); + } + + return null; + })} + + ); +}; // Essential overview part export const setEssentialOverviewSection = (contentManagement: ContentManagementPluginSetup) => { @@ -42,19 +57,7 @@ export const setEssentialOverviewSection = (contentManagement: ContentManagement order: 2000, title: 'Recently viewed', kind: 'custom', - render: (contents) => { - return ( - <> - {contents.map((content) => { - if (content.kind === 'custom') { - return content.render(); - } - - return null; - })} - - ); - }, + render: recentlyViewSectionRender, }, { id: SECTIONS.GET_STARTED, @@ -140,19 +143,7 @@ export const setAnalyticsAllOverviewSection = (contentManagement: ContentManagem order: 2000, title: 'Recently viewed', kind: 'custom', - render: (contents) => { - return ( - <> - {contents.map((content) => { - if (content.kind === 'custom') { - return content.render(); - } - - return null; - })} - - ); - }, + render: recentlyViewSectionRender, }, { id: SECTIONS.GET_STARTED, diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index 5b87b2521345..071d910b8fcd 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -266,7 +266,7 @@ describe('Workspace plugin', () => { expect(setupMock.application.register).toHaveBeenCalledWith( expect.objectContaining({ - id: 'essential_overview', + id: 'analytics_overview', }) ); }); @@ -291,7 +291,7 @@ describe('Workspace plugin', () => { expect(setupMock.application.register).toHaveBeenCalledWith( expect.objectContaining({ - id: 'analytics_all_overview', + id: 'all_overview', }) ); }); diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 177c1b54dd06..5bc05a59f650 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -31,8 +31,8 @@ import { WORKSPACE_LIST_APP_ID, WORKSPACE_USE_CASES, WORKSPACE_INITIAL_APP_ID, - ESSENTIAL_OVERVIEW_APP_ID, - ANALYTICS_OVERVIEW_ALL_APP_ID, + ESSENTIAL_OVERVIEW_PAGE_ID, + ANALYTICS_ALL_OVERVIEW_PAGE_ID, } from '../common/constants'; import { getWorkspaceIdFromUrl } from '../../../core/public/utils'; import { Services, WorkspaceUseCase } from './types'; @@ -135,14 +135,14 @@ export class WorkspacePlugin // disable essential overview page for workspace use case is not essential if ( - app.id === ESSENTIAL_OVERVIEW_APP_ID && + app.id === ESSENTIAL_OVERVIEW_PAGE_ID && workspaceUseCase !== WORKSPACE_USE_CASES.essentials.id ) { return { status: AppStatus.inaccessible }; } // disable analytics(All) overview page for workspace use case is not analytics(All) - if (app.id === ANALYTICS_OVERVIEW_ALL_APP_ID && workspaceUseCase !== ALL_USE_CASE_ID) { + if (app.id === ANALYTICS_ALL_OVERVIEW_PAGE_ID && workspaceUseCase !== ALL_USE_CASE_ID) { return { status: AppStatus.inaccessible }; } @@ -426,7 +426,7 @@ export class WorkspacePlugin if (core.chrome.navGroup.getNavGroupEnabled() && contentManagement) { // workspace essential use case overview core.application.register({ - id: ESSENTIAL_OVERVIEW_APP_ID, + id: ESSENTIAL_OVERVIEW_PAGE_ID, title: '', async mount(params: AppMountParameters) { const { renderUseCaseOverviewApp } = await import('./application'); @@ -441,14 +441,14 @@ export class WorkspacePlugin contentManagement: contentManagementStart, }; - return renderUseCaseOverviewApp(params, services, ESSENTIAL_OVERVIEW_APP_ID); + return renderUseCaseOverviewApp(params, services, ESSENTIAL_OVERVIEW_PAGE_ID); }, workspaceAvailability: WorkspaceAvailability.insideWorkspace, }); core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.essentials, [ { - id: ESSENTIAL_OVERVIEW_APP_ID, + id: ESSENTIAL_OVERVIEW_PAGE_ID, order: -1, title: i18n.translate('workspace.nav.essential_overview.title', { defaultMessage: 'Overview', @@ -461,7 +461,7 @@ export class WorkspacePlugin // register workspace Analytics(all) use case overview app core.application.register({ - id: ANALYTICS_OVERVIEW_ALL_APP_ID, + id: ANALYTICS_ALL_OVERVIEW_PAGE_ID, title: '', async mount(params: AppMountParameters) { const { renderUseCaseOverviewApp } = await import('./application'); @@ -476,14 +476,14 @@ export class WorkspacePlugin contentManagement: contentManagementStart, }; - return renderUseCaseOverviewApp(params, services, ANALYTICS_OVERVIEW_ALL_APP_ID); + return renderUseCaseOverviewApp(params, services, ANALYTICS_ALL_OVERVIEW_PAGE_ID); }, workspaceAvailability: WorkspaceAvailability.insideWorkspace, }); core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ { - id: ANALYTICS_OVERVIEW_ALL_APP_ID, + id: ANALYTICS_ALL_OVERVIEW_PAGE_ID, order: -1, title: i18n.translate('workspace.nav.analyticsAll_overview.title', { defaultMessage: 'Overview', diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index 4a2cd0cbc463..70d839691d41 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -13,6 +13,7 @@ import { ChromeBreadcrumb, ApplicationStart, HttpSetup, + DEFAULT_NAV_GROUPS, } from '../../../core/public'; import { App, @@ -23,7 +24,12 @@ import { WorkspaceObject, WorkspaceAvailability, } from '../../../core/public'; -import { DEFAULT_SELECTED_FEATURES_IDS, WORKSPACE_DETAIL_APP_ID } from '../common/constants'; +import { + ANALYTICS_ALL_OVERVIEW_PAGE_ID, + DEFAULT_SELECTED_FEATURES_IDS, + ESSENTIAL_OVERVIEW_PAGE_ID, + WORKSPACE_DETAIL_APP_ID, +} from '../common/constants'; import { WorkspaceUseCase } from './types'; import { formatUrlWithWorkspaceId } from '../../../core/public/utils'; import { SigV4ServiceName } from '../../../plugins/data_source/common/data_sources'; @@ -312,7 +318,11 @@ export function prependWorkspaceToBreadcrumbs( currentNavGroup: NavGroupItemInMap | undefined, navGroupsMap: Record ) { - if (appId === WORKSPACE_DETAIL_APP_ID) { + if ( + appId === WORKSPACE_DETAIL_APP_ID || + appId === ESSENTIAL_OVERVIEW_PAGE_ID || + appId === ANALYTICS_ALL_OVERVIEW_PAGE_ID + ) { core.chrome.setBreadcrumbsEnricher(undefined); return; } @@ -358,7 +368,7 @@ export function prependWorkspaceToBreadcrumbs( }, }; if (useCase === ALL_USE_CASE_ID) { - if (currentNavGroup) { + if (currentNavGroup && currentNavGroup.id !== DEFAULT_NAV_GROUPS.all.id) { return [homeBreadcrumb, workspaceBreadcrumb, navGroupBreadcrumb, ...breadcrumbs]; } else { return [homeBreadcrumb, workspaceBreadcrumb, ...breadcrumbs]; From 6c57a4d7729a07ec2d6bd06b18059924c6d3ec26 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Thu, 22 Aug 2024 18:24:49 +0800 Subject: [PATCH 13/20] fix import sample data target area Signed-off-by: Hailong Cui --- .../components/sample_data/sample_data_card.test.tsx | 2 +- .../application/components/sample_data/sample_data_card.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx index 50ac28e1e815..a680cdbc46aa 100644 --- a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx @@ -20,7 +20,7 @@ describe('Sample data card', () => { it('should call the getTargetArea function with the correct arguments', () => { registerSampleDataCard(contentManagement, coreStart); const call = registerContentProviderMock.mock.calls[0]; - expect(call[0].getTargetArea()).toEqual(['essential_overview/get_started']); + expect(call[0].getTargetArea()).toEqual(['analytics_overview/get_started']); expect(call[0].getContent()).toMatchInlineSnapshot(` Object { "cardProps": Object { diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx index c8ea197f39fb..eab15dad289f 100644 --- a/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx @@ -16,7 +16,7 @@ export const registerSampleDataCard = ( ) => { contentManagement.registerContentProvider({ id: `get_start_sample_data`, - getTargetArea: () => ['essential_overview/get_started'], + getTargetArea: () => ['analytics_overview/get_started'], getContent: () => ({ id: 'sample_data', kind: 'card', From 5196017579f9ac63637bf3ba7533d6d3832a5657 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Fri, 23 Aug 2024 00:22:38 +0800 Subject: [PATCH 14/20] workspace icon Signed-off-by: Hailong Cui --- src/core/utils/default_nav_groups.ts | 5 +++++ .../public/components/use_case_overview/setup_overview.tsx | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/core/utils/default_nav_groups.ts b/src/core/utils/default_nav_groups.ts index 64fea126ff3e..43370fcdb94d 100644 --- a/src/core/utils/default_nav_groups.ts +++ b/src/core/utils/default_nav_groups.ts @@ -40,6 +40,7 @@ const defaultNavGroups = { defaultMessage: 'This is a use case contains all the features.', }), order: 3000, + icon: 'wsAnalytics', }, observability: { id: 'observability', @@ -51,6 +52,7 @@ const defaultNavGroups = { 'Gain visibility into system health, performance, and reliability through monitoring and analysis of logs, metrics, and traces.', }), order: 4000, + icon: 'wsObservability', }, 'security-analytics': { id: 'security-analytics', @@ -62,6 +64,7 @@ const defaultNavGroups = { 'Detect and investigate potential security threats and vulnerabilities across your systems and data.', }), order: 5000, + icon: 'wsSecurityAnalytics', }, essentials: { id: 'analytics', @@ -73,6 +76,7 @@ const defaultNavGroups = { 'Analyze data to derive insights, identify patterns and trends, and make data-driven decisions.', }), order: 7000, + icon: 'wsEssentials', }, search: { id: 'search', @@ -84,6 +88,7 @@ const defaultNavGroups = { "Quickly find and explore relevant information across your organization's data sources.", }), order: 6000, + icon: 'wsSearch', }, } as const; diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx index a1814c505a61..a6d2b161943c 100644 --- a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx @@ -170,7 +170,8 @@ export const registerAnalyticsAllOverviewContent = ( getContent: () => ({ id: card.id, kind: 'card', - getIcon: () => React.createElement(EuiIcon, { size: 'xl', type: 'spacesApp' }), + getIcon: () => + React.createElement(EuiIcon, { size: 'xl', type: card.icon || 'wsSelector' }), order: card.order || index, description: card.description, title: card.title, From ea292a9c3fe9072e6317b5934f8e1dbe31d37250 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Fri, 23 Aug 2024 12:06:18 +0800 Subject: [PATCH 15/20] move all content ids to content management plugin Signed-off-by: Hailong Cui --- .../content_management/public/constants.ts | 36 +++++++++++++++++++ .../content_management/public/index.ts | 1 + src/plugins/home/common/constants.ts | 12 ------- .../public/application/components/home_app.js | 3 +- .../sample_data/sample_data_card.test.tsx | 2 +- .../sample_data/sample_data_card.tsx | 9 +++-- .../home/public/application/home_render.tsx | 4 ++- .../opensearch_dashboards.json | 2 +- .../saved_objects_management/public/plugin.ts | 10 ++++-- src/plugins/workspace/common/constants.ts | 20 ----------- .../workspace/opensearch_dashboards.json | 2 +- .../use_case_overview/setup_overview.tsx | 4 +-- src/plugins/workspace/public/plugin.ts | 6 ++-- src/plugins/workspace/public/utils.ts | 11 +++--- 14 files changed, 67 insertions(+), 55 deletions(-) create mode 100644 src/plugins/content_management/public/constants.ts diff --git a/src/plugins/content_management/public/constants.ts b/src/plugins/content_management/public/constants.ts new file mode 100644 index 000000000000..e15e23b9bb4e --- /dev/null +++ b/src/plugins/content_management/public/constants.ts @@ -0,0 +1,36 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +// central place for all content ids rendered by content management + +// page ids +export const ESSENTIAL_OVERVIEW_PAGE_ID = 'analytics_overview'; +export const ANALYTICS_ALL_OVERVIEW_PAGE_ID = 'all_overview'; +export const HOME_PAGE_ID = 'osd_homepage'; + +// section ids +export enum SECTIONS { + GET_STARTED = `get_started`, + SERVICE_CARDS = `service_cards`, + RECENTLY_VIEWED = `recently_viewed`, +} + +export enum HOME_CONTENT_AREAS { + GET_STARTED = `${HOME_PAGE_ID}/${SECTIONS.GET_STARTED}`, + SERVICE_CARDS = `${HOME_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, + RECENTLY_VIEWED = `${HOME_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, +} + +export enum ESSENTIAL_OVERVIEW_CONTENT_AREAS { + GET_STARTED = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, + SERVICE_CARDS = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, + RECENTLY_VIEWED = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, +} + +export enum ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS { + GET_STARTED = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, + SERVICE_CARDS = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, + RECENTLY_VIEWED = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, +} diff --git a/src/plugins/content_management/public/index.ts b/src/plugins/content_management/public/index.ts index 4ecd28b3942a..029e778d559b 100644 --- a/src/plugins/content_management/public/index.ts +++ b/src/plugins/content_management/public/index.ts @@ -14,3 +14,4 @@ export const plugin = (initializerContext: PluginInitializerContext) => export * from './components'; export * from './mocks'; export * from './services/content_management'; +export * from './constants'; diff --git a/src/plugins/home/common/constants.ts b/src/plugins/home/common/constants.ts index 6d5c74267be0..25c78c59c4ac 100644 --- a/src/plugins/home/common/constants.ts +++ b/src/plugins/home/common/constants.ts @@ -32,15 +32,3 @@ export const PLUGIN_ID = 'home'; export const HOME_APP_BASE_PATH = `/app/${PLUGIN_ID}`; export const USE_NEW_HOME_PAGE = 'home:useNewHomePage'; export const IMPORT_SAMPLE_DATA_APP_ID = 'import_sample_data'; -export const HOME_PAGE_ID = 'osd_homepage'; -export enum SECTIONS { - GET_STARTED = `get_started`, - SERVICE_CARDS = `service_cards`, - RECENTLY_VIEWED = `recently_viewed`, -} - -export enum HOME_CONTENT_AREAS { - GET_STARTED = `${HOME_PAGE_ID}/${SECTIONS.GET_STARTED}`, - SERVICE_CARDS = `${HOME_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, - RECENTLY_VIEWED = `${HOME_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, -} diff --git a/src/plugins/home/public/application/components/home_app.js b/src/plugins/home/public/application/components/home_app.js index 4eb253a9cdd0..61596c724310 100644 --- a/src/plugins/home/public/application/components/home_app.js +++ b/src/plugins/home/public/application/components/home_app.js @@ -40,7 +40,8 @@ import { getTutorial } from '../load_tutorials'; import { replaceTemplateStrings } from './tutorial/replace_template_strings'; import { getServices } from '../opensearch_dashboards_services'; import { useMount } from 'react-use'; -import { USE_NEW_HOME_PAGE, HOME_PAGE_ID } from '../../../common/constants'; +import { USE_NEW_HOME_PAGE } from '../../../common/constants'; +import { HOME_PAGE_ID } from '../../../../content_management/public'; const RedirectToDefaultApp = () => { useMount(() => { diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx index a680cdbc46aa..f333743796df 100644 --- a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx @@ -33,7 +33,7 @@ describe('Sample data card', () => { "onClick": [Function], }, }, - "description": "Explore sample data before adding your own.", + "description": "You can install sample data to experiment with OpenSearch Dashboards.", "id": "sample_data", "kind": "card", "order": 0, diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx index eab15dad289f..4deb4eb8ff59 100644 --- a/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx @@ -7,7 +7,10 @@ import { CoreStart } from 'opensearch-dashboards/public'; import React from 'react'; import { EuiI18n } from '@elastic/eui'; import { i18n } from '@osd/i18n'; -import { ContentManagementPluginStart } from '../../../../../content_management/public'; +import { + ContentManagementPluginStart, + ESSENTIAL_OVERVIEW_CONTENT_AREAS, +} from '../../../../../content_management/public'; import { IMPORT_SAMPLE_DATA_APP_ID } from '../../../../common/constants'; export const registerSampleDataCard = ( @@ -16,13 +19,13 @@ export const registerSampleDataCard = ( ) => { contentManagement.registerContentProvider({ id: `get_start_sample_data`, - getTargetArea: () => ['analytics_overview/get_started'], + getTargetArea: () => [ESSENTIAL_OVERVIEW_CONTENT_AREAS.GET_STARTED], getContent: () => ({ id: 'sample_data', kind: 'card', order: 0, description: i18n.translate('home.sampleData.card.description', { - defaultMessage: 'Explore sample data before adding your own.', + defaultMessage: 'You can install sample data to experiment with OpenSearch Dashboards.', }), title: i18n.translate('home.sampleData.card.title', { defaultMessage: 'Try openSearch', diff --git a/src/plugins/home/public/application/home_render.tsx b/src/plugins/home/public/application/home_render.tsx index afddae56ce63..5e46d61e883a 100644 --- a/src/plugins/home/public/application/home_render.tsx +++ b/src/plugins/home/public/application/home_render.tsx @@ -8,8 +8,10 @@ import { CoreStart } from 'opensearch-dashboards/public'; import { ContentManagementPluginSetup, ContentManagementPluginStart, + HOME_PAGE_ID, + SECTIONS, + HOME_CONTENT_AREAS, } from '../../../../plugins/content_management/public'; -import { HOME_PAGE_ID, SECTIONS, HOME_CONTENT_AREAS } from '../../common/constants'; import { WHATS_NEW_CONFIG, LEARN_OPENSEARCH_CONFIG, diff --git a/src/plugins/saved_objects_management/opensearch_dashboards.json b/src/plugins/saved_objects_management/opensearch_dashboards.json index 9a985345b030..5b6236ad2630 100644 --- a/src/plugins/saved_objects_management/opensearch_dashboards.json +++ b/src/plugins/saved_objects_management/opensearch_dashboards.json @@ -16,5 +16,5 @@ "contentManagement" ], "extraPublicDirs": ["public/lib"], - "requiredBundles": ["opensearchDashboardsReact", "home"] + "requiredBundles": ["opensearchDashboardsReact", "home", "contentManagement"] } diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts index 11912203f1f2..785ac404528a 100644 --- a/src/plugins/saved_objects_management/public/plugin.ts +++ b/src/plugins/saved_objects_management/public/plugin.ts @@ -65,7 +65,11 @@ import { registerServices } from './register_services'; import { bootstrap } from './ui_actions_bootstrap'; import { DEFAULT_NAV_GROUPS } from '../../../core/public'; import { RecentWork } from './management_section/recent_work'; -import { HOME_CONTENT_AREAS } from '../../../plugins/home/public'; +import { + HOME_CONTENT_AREAS, + ESSENTIAL_OVERVIEW_CONTENT_AREAS, + ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS, +} from '../../../plugins/content_management/public'; import { getScopedBreadcrumbs } from '../../opensearch_dashboards_react/public'; import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; @@ -238,8 +242,8 @@ export class SavedObjectsManagementPlugin }, getTargetArea: () => [ HOME_CONTENT_AREAS.RECENTLY_VIEWED, - 'analytics_overview/recently_viewed', - 'all_overview/recently_viewed', + ESSENTIAL_OVERVIEW_CONTENT_AREAS.RECENTLY_VIEWED, + ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.RECENTLY_VIEWED, ], }); diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index fede6a8cc9ca..325174031e0b 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -150,23 +150,3 @@ export const CURRENT_USER_PLACEHOLDER = '%me%'; export const MAX_WORKSPACE_NAME_LENGTH = 40; export const MAX_WORKSPACE_DESCRIPTION_LENGTH = 200; -// pattern for the page id is useCaseId_overview -export const ESSENTIAL_OVERVIEW_PAGE_ID = 'analytics_overview'; -export const ANALYTICS_ALL_OVERVIEW_PAGE_ID = 'all_overview'; -export enum SECTIONS { - GET_STARTED = `get_started`, - SERVICE_CARDS = `service_cards`, - RECENTLY_VIEWED = `recently_viewed`, -} - -export enum ESSENTIAL_OVERVIEW_CONTENT_AREAS { - GET_STARTED = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, - SERVICE_CARDS = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, - RECENTLY_VIEWED = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, -} - -export enum ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS { - GET_STARTED = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, - SERVICE_CARDS = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, - RECENTLY_VIEWED = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, -} diff --git a/src/plugins/workspace/opensearch_dashboards.json b/src/plugins/workspace/opensearch_dashboards.json index ac24c20d712b..9346d7a8fe32 100644 --- a/src/plugins/workspace/opensearch_dashboards.json +++ b/src/plugins/workspace/opensearch_dashboards.json @@ -9,5 +9,5 @@ "navigation" ], "optionalPlugins": ["savedObjectsManagement","management","dataSourceManagement","contentManagement"], - "requiredBundles": ["opensearchDashboardsReact", "home","dataSource"] + "requiredBundles": ["opensearchDashboardsReact","dataSource", "contentManagement"] } diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx index a6d2b161943c..2df27ab9c1d2 100644 --- a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx @@ -10,14 +10,12 @@ import { first } from 'rxjs/operators'; import { ContentManagementPluginSetup, ContentManagementPluginStart, -} from '../../../../content_management/public'; -import { ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS, ANALYTICS_ALL_OVERVIEW_PAGE_ID, ESSENTIAL_OVERVIEW_CONTENT_AREAS, ESSENTIAL_OVERVIEW_PAGE_ID, SECTIONS, -} from '../../../common/constants'; +} from '../../../../content_management/public'; import { getStartedCards } from './get_started_cards'; import { HomeListCard, diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index a14f38f7cd0f..f4845c0e11e7 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -31,8 +31,6 @@ import { WORKSPACE_LIST_APP_ID, WORKSPACE_USE_CASES, WORKSPACE_INITIAL_APP_ID, - ESSENTIAL_OVERVIEW_PAGE_ID, - ANALYTICS_ALL_OVERVIEW_PAGE_ID, } from '../common/constants'; import { getWorkspaceIdFromUrl } from '../../../core/public/utils'; import { Services, WorkspaceUseCase } from './types'; @@ -40,8 +38,10 @@ import { WorkspaceClient } from './workspace_client'; import { SavedObjectsManagementPluginSetup } from '../../../plugins/saved_objects_management/public'; import { ManagementSetup } from '../../../plugins/management/public'; import { + ANALYTICS_ALL_OVERVIEW_PAGE_ID, ContentManagementPluginSetup, ContentManagementPluginStart, + ESSENTIAL_OVERVIEW_PAGE_ID, } from '../../../plugins/content_management/public'; import { WorkspaceMenu } from './components/workspace_menu/workspace_menu'; import { getWorkspaceColumn } from './components/workspace_column'; @@ -59,7 +59,7 @@ import { UseCaseService } from './services/use_case_service'; import { WorkspaceListCard } from './components/service_card'; import { UseCaseFooter } from './components/home_get_start_card'; import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; -import { HOME_CONTENT_AREAS } from '../../../plugins/home/public'; +import { HOME_CONTENT_AREAS } from '../../../plugins/content_management/public'; import { registerEssentialOverviewContent, setEssentialOverviewSection, diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index 3a5ec97da901..b94a7f2f180a 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -24,15 +24,14 @@ import { WorkspaceObject, WorkspaceAvailability, } from '../../../core/public'; -import { - ANALYTICS_ALL_OVERVIEW_PAGE_ID, - DEFAULT_SELECTED_FEATURES_IDS, - ESSENTIAL_OVERVIEW_PAGE_ID, - WORKSPACE_DETAIL_APP_ID, -} from '../common/constants'; +import { DEFAULT_SELECTED_FEATURES_IDS, WORKSPACE_DETAIL_APP_ID } from '../common/constants'; import { WorkspaceUseCase } from './types'; import { formatUrlWithWorkspaceId } from '../../../core/public/utils'; import { SigV4ServiceName } from '../../../plugins/data_source/common/data_sources'; +import { + ANALYTICS_ALL_OVERVIEW_PAGE_ID, + ESSENTIAL_OVERVIEW_PAGE_ID, +} from '../../../plugins/content_management/public'; export const USE_CASE_PREFIX = 'use-case-'; From a57a5220d1a700cd2995e1f976cad81079c890ee Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Fri, 23 Aug 2024 15:31:31 +0800 Subject: [PATCH 16/20] refactor whats_new and learn opensearch Signed-off-by: Hailong Cui --- .../content_management/public/constants.ts | 9 +++ .../application/components/home_list_card.tsx | 68 +++++++++++++++++++ .../home/public/application/home_render.tsx | 39 ++++------- src/plugins/home/public/index.ts | 8 --- src/plugins/home/public/plugin.ts | 4 ++ .../workspace/opensearch_dashboards.json | 2 +- .../use_case_overview/setup_overview.test.tsx | 56 +-------------- .../use_case_overview/setup_overview.tsx | 67 ------------------ 8 files changed, 98 insertions(+), 155 deletions(-) diff --git a/src/plugins/content_management/public/constants.ts b/src/plugins/content_management/public/constants.ts index e15e23b9bb4e..6d31b92b4eaa 100644 --- a/src/plugins/content_management/public/constants.ts +++ b/src/plugins/content_management/public/constants.ts @@ -9,12 +9,15 @@ export const ESSENTIAL_OVERVIEW_PAGE_ID = 'analytics_overview'; export const ANALYTICS_ALL_OVERVIEW_PAGE_ID = 'all_overview'; export const HOME_PAGE_ID = 'osd_homepage'; +export const SEARCH_OVERVIEW_ID = 'search_overview'; // section ids export enum SECTIONS { GET_STARTED = `get_started`, SERVICE_CARDS = `service_cards`, RECENTLY_VIEWED = `recently_viewed`, + DIFFERENT_SEARCH_TYPES = 'different_search_types', + CONFIG_EVALUATE_SEARCH = 'config_evaluate_search', } export enum HOME_CONTENT_AREAS { @@ -34,3 +37,9 @@ export enum ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS { SERVICE_CARDS = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, RECENTLY_VIEWED = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, } + +export enum SEARCH_OVERVIEW_CONTENT_AREAS { + DIFFERENT_SEARCH_TYPES = `${SEARCH_OVERVIEW_ID}/${SECTIONS.DIFFERENT_SEARCH_TYPES}`, + CONFIG_EVALUATE_SEARCH = `${SEARCH_OVERVIEW_ID}/${SECTIONS.CONFIG_EVALUATE_SEARCH}`, + GET_STARTED = `${SEARCH_OVERVIEW_ID}/${SECTIONS.GET_STARTED}`, +} diff --git a/src/plugins/home/public/application/components/home_list_card.tsx b/src/plugins/home/public/application/components/home_list_card.tsx index e584635c680e..2d1cee86f838 100644 --- a/src/plugins/home/public/application/components/home_list_card.tsx +++ b/src/plugins/home/public/application/components/home_list_card.tsx @@ -17,6 +17,11 @@ import { EuiFlexItem, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; +import { + ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS, + ContentManagementPluginStart, + ESSENTIAL_OVERVIEW_CONTENT_AREAS, +} from '../../../../content_management/public'; export const LEARN_OPENSEARCH_CONFIG = { title: i18n.translate('homepage.card.learnOpenSearch.title', { @@ -116,3 +121,66 @@ export const HomeListCard = ({ config }: { config: Config }) => { ); }; + +export const registerHomeListCard = ( + contentManagement: ContentManagementPluginStart, + { + target, + order, + width, + config, + id, + }: { + target: string; + order: number; + width?: number; + config: Config; + id: string; + } +) => { + contentManagement.registerContentProvider({ + id: `${id}_${target}_cards`, + getContent: () => ({ + id, + kind: 'custom', + order, + width, + render: () => + React.createElement(HomeListCard, { + config, + }), + }), + getTargetArea: () => target, + }); +}; +export const registerHomeListCardToPage = (contentManagement: ContentManagementPluginStart) => { + registerHomeListCard(contentManagement, { + id: 'whats_new', + order: 10, + config: WHATS_NEW_CONFIG, + target: ESSENTIAL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + width: 24, + }); + + registerHomeListCard(contentManagement, { + id: 'learn_opensearch_new', + order: 20, + config: LEARN_OPENSEARCH_CONFIG, + target: ESSENTIAL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + width: 24, + }); + + registerHomeListCard(contentManagement, { + id: 'whats_new', + order: 30, + config: WHATS_NEW_CONFIG, + target: ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + }); + + registerHomeListCard(contentManagement, { + id: 'learn_opensearch_new', + order: 40, + config: LEARN_OPENSEARCH_CONFIG, + target: ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + }); +}; diff --git a/src/plugins/home/public/application/home_render.tsx b/src/plugins/home/public/application/home_render.tsx index 5e46d61e883a..03babca342eb 100644 --- a/src/plugins/home/public/application/home_render.tsx +++ b/src/plugins/home/public/application/home_render.tsx @@ -15,7 +15,7 @@ import { import { WHATS_NEW_CONFIG, LEARN_OPENSEARCH_CONFIG, - HomeListCard, + registerHomeListCard, } from './components/home_list_card'; export const setupHome = (contentManagement: ContentManagementPluginSetup) => { @@ -58,30 +58,19 @@ export const setupHome = (contentManagement: ContentManagementPluginSetup) => { }; export const initHome = (contentManagement: ContentManagementPluginStart, core: CoreStart) => { - contentManagement.registerContentProvider({ - id: 'whats_new_cards', - getContent: () => ({ - id: 'whats_new', - kind: 'custom', - order: 3, - render: () => - React.createElement(HomeListCard, { - config: WHATS_NEW_CONFIG, - }), - }), - getTargetArea: () => HOME_CONTENT_AREAS.SERVICE_CARDS, + registerHomeListCard(contentManagement, { + id: 'whats_new', + order: 3, + config: WHATS_NEW_CONFIG, + target: HOME_CONTENT_AREAS.SERVICE_CARDS, + width: 16, }); - contentManagement.registerContentProvider({ - id: 'learn_opensearch_new_cards', - getContent: () => ({ - id: 'learn_opensearch', - kind: 'custom', - order: 4, - render: () => - React.createElement(HomeListCard, { - config: LEARN_OPENSEARCH_CONFIG, - }), - }), - getTargetArea: () => HOME_CONTENT_AREAS.SERVICE_CARDS, + + registerHomeListCard(contentManagement, { + id: 'learn_opensearch_new', + order: 4, + config: LEARN_OPENSEARCH_CONFIG, + target: HOME_CONTENT_AREAS.SERVICE_CARDS, + width: 16, }); }; diff --git a/src/plugins/home/public/index.ts b/src/plugins/home/public/index.ts index 18f321fc87d3..58ad10cdf04b 100644 --- a/src/plugins/home/public/index.ts +++ b/src/plugins/home/public/index.ts @@ -53,11 +53,3 @@ import { HomePublicPlugin } from './plugin'; export const plugin = (initializerContext: PluginInitializerContext) => new HomePublicPlugin(initializerContext); - -export { HOME_PAGE_ID, HOME_CONTENT_AREAS } from '../common/constants'; - -export { - HomeListCard, - WHATS_NEW_CONFIG, - LEARN_OPENSEARCH_CONFIG, -} from '../public/application/components/home_list_card'; diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index afa8dffd5e42..21a35e151d54 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -71,6 +71,7 @@ import { } from '../../content_management/public'; import { initHome, setupHome } from './application/home_render'; import { registerSampleDataCard } from './application/components/sample_data/sample_data_card'; +import { registerHomeListCardToPage } from './application/components/home_list_card'; export interface HomePluginStartDependencies { data: DataPublicPluginStart; @@ -242,6 +243,9 @@ export class HomePublicPlugin // register sample data card to use case overview page registerSampleDataCard(contentManagement, core); + // register what's new learn opensearch card to use case overview page + registerHomeListCardToPage(contentManagement); + this.featuresCatalogueRegistry.start({ capabilities }); this.sectionTypeService.start({ core, data }); diff --git a/src/plugins/workspace/opensearch_dashboards.json b/src/plugins/workspace/opensearch_dashboards.json index 9346d7a8fe32..9818ab60966d 100644 --- a/src/plugins/workspace/opensearch_dashboards.json +++ b/src/plugins/workspace/opensearch_dashboards.json @@ -9,5 +9,5 @@ "navigation" ], "optionalPlugins": ["savedObjectsManagement","management","dataSourceManagement","contentManagement"], - "requiredBundles": ["opensearchDashboardsReact","dataSource", "contentManagement"] + "requiredBundles": ["opensearchDashboardsReact","dataSource","contentManagement"] } diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx index f457a3638b36..0d8733a21ce7 100644 --- a/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx @@ -68,7 +68,7 @@ describe('Setup use case overview', () => { registerEssentialOverviewContent(contentManagementStartMock, coreStart); const calls = registerContentProviderMock.mock.calls; - expect(calls.length).toBe(5); + expect(calls.length).toBe(3); const firstCall = calls[0]; expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot(`"analytics_overview/get_started"`); @@ -91,32 +91,6 @@ describe('Setup use case overview', () => { "title": "Discover insights", } `); - - const whatsNew = calls[3]; - expect(whatsNew[0].getTargetArea()).toMatchInlineSnapshot(`"analytics_overview/service_cards"`); - expect(whatsNew[0].getContent()).toMatchInlineSnapshot(` - Object { - "id": "whats_new", - "kind": "custom", - "order": 10, - "render": [Function], - "width": 24, - } - `); - - const learnOpenSearch = calls[4]; - expect(learnOpenSearch[0].getTargetArea()).toMatchInlineSnapshot( - `"analytics_overview/service_cards"` - ); - expect(learnOpenSearch[0].getContent()).toMatchInlineSnapshot(` - Object { - "id": "learn_opensearch", - "kind": "custom", - "order": 20, - "render": [Function], - "width": 24, - } - `); }); it('setAnalyticsAllOverviewSection', () => { @@ -154,7 +128,7 @@ describe('Setup use case overview', () => { registerAnalyticsAllOverviewContent(contentManagementStartMock, coreStart); const calls = registerContentProviderMock.mock.calls; - expect(calls.length).toBe(5); + expect(calls.length).toBe(3); const firstCall = calls[0]; expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot(`"all_overview/get_started"`); @@ -172,31 +146,5 @@ describe('Setup use case overview', () => { "title": "Observability", } `); - - const whatsNew = calls[3]; - expect(whatsNew[0].getTargetArea()).toMatchInlineSnapshot(`"all_overview/service_cards"`); - expect(whatsNew[0].getContent()).toMatchInlineSnapshot(` - Object { - "id": "whats_new", - "kind": "custom", - "order": 30, - "render": [Function], - "width": 12, - } - `); - - const learnOpenSearch = calls[4]; - expect(learnOpenSearch[0].getTargetArea()).toMatchInlineSnapshot( - `"all_overview/service_cards"` - ); - expect(learnOpenSearch[0].getContent()).toMatchInlineSnapshot(` - Object { - "id": "learn_opensearch", - "kind": "custom", - "order": 40, - "render": [Function], - "width": 12, - } - `); }); }); diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx index 2df27ab9c1d2..4b801bf0880d 100644 --- a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx @@ -17,11 +17,6 @@ import { SECTIONS, } from '../../../../content_management/public'; import { getStartedCards } from './get_started_cards'; -import { - HomeListCard, - LEARN_OPENSEARCH_CONFIG, - WHATS_NEW_CONFIG, -} from '../../../../../plugins/home/public'; import { DEFAULT_NAV_GROUPS } from '../../../../../core/public'; import { Content } from '../../../../../plugins/content_management/public'; @@ -92,37 +87,6 @@ export const registerEssentialOverviewContent = ( }), }); }); - - // card - contentManagement.registerContentProvider({ - id: 'whats_new_cards_essential_overview', - getContent: () => ({ - id: 'whats_new', - kind: 'custom', - order: 10, - width: 24, - render: () => - React.createElement(HomeListCard, { - config: WHATS_NEW_CONFIG, - }), - }), - getTargetArea: () => ESSENTIAL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, - }); - - contentManagement.registerContentProvider({ - id: 'learn_opensearch_cards_essential_overview', - getContent: () => ({ - id: 'learn_opensearch', - kind: 'custom', - order: 20, - width: 24, - render: () => - React.createElement(HomeListCard, { - config: LEARN_OPENSEARCH_CONFIG, - }), - }), - getTargetArea: () => ESSENTIAL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, - }); }; // Analytics(All) overview part @@ -187,35 +151,4 @@ export const registerAnalyticsAllOverviewContent = ( }), }); }); - - // card - contentManagement.registerContentProvider({ - id: 'whats_new_cards_essential_overview', - getContent: () => ({ - id: 'whats_new', - kind: 'custom', - order: 30, - width: 12, - render: () => - React.createElement(HomeListCard, { - config: WHATS_NEW_CONFIG, - }), - }), - getTargetArea: () => ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, - }); - - contentManagement.registerContentProvider({ - id: 'learn_opensearch_cards_essential_overview', - getContent: () => ({ - id: 'learn_opensearch', - kind: 'custom', - order: 40, - width: 12, - render: () => - React.createElement(HomeListCard, { - config: LEARN_OPENSEARCH_CONFIG, - }), - }), - getTargetArea: () => ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, - }); }; From 531cf00b62ba4dac76f9f499b05e1d273897e0b8 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Fri, 23 Aug 2024 15:37:05 +0800 Subject: [PATCH 17/20] fix merge issue Signed-off-by: Hailong Cui --- .../components/workspace_detail/workspace_detail_panel.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx index 81f50b568887..6ada5490c379 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx @@ -48,9 +48,8 @@ function getOwners(currentWorkspace: WorkspaceAttributeWithPermission) { if (currentWorkspace.permissions) { const { groups = [], users = [] } = currentWorkspace.permissions.write; return [...groups, ...users]; - } else { - return []; } + return []; } interface WorkspaceDetailPanelProps { From 34b3442560ca6929d57eb5fdde4bba7ccecbcac7 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Sat, 24 Aug 2024 12:16:43 +0800 Subject: [PATCH 18/20] fix merge issue Signed-off-by: Hailong Cui --- src/plugins/workspace/public/plugin.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 112256172dc9..03c6b544b64d 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -127,7 +127,16 @@ export class WorkspacePlugin this.registeredUseCases$, ]).subscribe(([currentWorkspace, registeredUseCases]) => { if (currentWorkspace) { + const workspaceUseCase = currentWorkspace.features + ? getFirstUseCaseOfFeatureConfigs(currentWorkspace.features) + : undefined; + this.appUpdater$.next((app) => { + // essential use overview is only available in essential workspace + if (app.id === ESSENTIAL_OVERVIEW_PAGE_ID && workspaceUseCase === ALL_USE_CASE_ID) { + return { status: AppStatus.inaccessible }; + } + if (isAppAccessibleInWorkspace(app, currentWorkspace, registeredUseCases)) { return; } From c5ca867e5b7a15df4f983ef01dab8cf405d186e2 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Mon, 26 Aug 2024 12:22:18 +0800 Subject: [PATCH 19/20] unify use case page content id Signed-off-by: Hailong Cui --- src/core/public/index.ts | 4 ++++ src/core/utils/default_nav_groups.ts | 12 ++++++---- src/core/utils/index.ts | 9 +++++++- .../content_management/public/constants.ts | 22 ++++++++++++++----- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 979e618fb505..99688dde73a6 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -112,6 +112,10 @@ export { cleanWorkspaceId, DEFAULT_NAV_GROUPS, ALL_USE_CASE_ID, + SEARCH_USE_CASE_ID, + ESSENTIAL_USE_CASE_ID, + OBSERVABILITY_USE_CASE_ID, + SECURITY_ANALYTICS_USE_CASE_ID, } from '../utils'; export { AppCategory, diff --git a/src/core/utils/default_nav_groups.ts b/src/core/utils/default_nav_groups.ts index 43370fcdb94d..7b3820ccfbd3 100644 --- a/src/core/utils/default_nav_groups.ts +++ b/src/core/utils/default_nav_groups.ts @@ -7,6 +7,10 @@ import { i18n } from '@osd/i18n'; import { ChromeNavGroup, NavGroupType } from '../types'; export const ALL_USE_CASE_ID = 'all'; +export const OBSERVABILITY_USE_CASE_ID = 'observability'; +export const SECURITY_ANALYTICS_USE_CASE_ID = 'security-analytics'; +export const ESSENTIAL_USE_CASE_ID = 'analytics'; +export const SEARCH_USE_CASE_ID = 'search'; const defaultNavGroups = { dataAdministration: { @@ -43,7 +47,7 @@ const defaultNavGroups = { icon: 'wsAnalytics', }, observability: { - id: 'observability', + id: OBSERVABILITY_USE_CASE_ID, title: i18n.translate('core.ui.group.observability.title', { defaultMessage: 'Observability', }), @@ -55,7 +59,7 @@ const defaultNavGroups = { icon: 'wsObservability', }, 'security-analytics': { - id: 'security-analytics', + id: SECURITY_ANALYTICS_USE_CASE_ID, title: i18n.translate('core.ui.group.security.analytics.title', { defaultMessage: 'Security Analytics', }), @@ -67,7 +71,7 @@ const defaultNavGroups = { icon: 'wsSecurityAnalytics', }, essentials: { - id: 'analytics', + id: ESSENTIAL_USE_CASE_ID, title: i18n.translate('core.ui.group.essential.title', { defaultMessage: 'Essentials', }), @@ -79,7 +83,7 @@ const defaultNavGroups = { icon: 'wsEssentials', }, search: { - id: 'search', + id: SEARCH_USE_CASE_ID, title: i18n.translate('core.ui.group.search.title', { defaultMessage: 'Search', }), diff --git a/src/core/utils/index.ts b/src/core/utils/index.ts index 46304c4bde3d..3cb5f43d843c 100644 --- a/src/core/utils/index.ts +++ b/src/core/utils/index.ts @@ -39,4 +39,11 @@ export { export { DEFAULT_APP_CATEGORIES } from './default_app_categories'; export { WORKSPACE_PATH_PREFIX, WORKSPACE_TYPE } from './constants'; export { getWorkspaceIdFromUrl, formatUrlWithWorkspaceId, cleanWorkspaceId } from './workspace'; -export { DEFAULT_NAV_GROUPS, ALL_USE_CASE_ID } from './default_nav_groups'; +export { + DEFAULT_NAV_GROUPS, + ALL_USE_CASE_ID, + SEARCH_USE_CASE_ID, + ESSENTIAL_USE_CASE_ID, + OBSERVABILITY_USE_CASE_ID, + SECURITY_ANALYTICS_USE_CASE_ID, +} from './default_nav_groups'; diff --git a/src/plugins/content_management/public/constants.ts b/src/plugins/content_management/public/constants.ts index 6d31b92b4eaa..e1d4ab07ecbc 100644 --- a/src/plugins/content_management/public/constants.ts +++ b/src/plugins/content_management/public/constants.ts @@ -3,13 +3,23 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { + ESSENTIAL_USE_CASE_ID, + ALL_USE_CASE_ID, + SEARCH_USE_CASE_ID, + OBSERVABILITY_USE_CASE_ID, + SECURITY_ANALYTICS_USE_CASE_ID, +} from '../../../core/public'; + // central place for all content ids rendered by content management // page ids -export const ESSENTIAL_OVERVIEW_PAGE_ID = 'analytics_overview'; -export const ANALYTICS_ALL_OVERVIEW_PAGE_ID = 'all_overview'; +export const ANALYTICS_ALL_OVERVIEW_PAGE_ID = `${ALL_USE_CASE_ID}_overview`; +export const ESSENTIAL_OVERVIEW_PAGE_ID = `${ESSENTIAL_USE_CASE_ID}_overview`; +export const SEARCH_OVERVIEW_PAGE_ID = `${SEARCH_USE_CASE_ID}_overview`; +export const OBSERVABILITY_OVERVIEW_PAGE_ID = `${OBSERVABILITY_USE_CASE_ID}_overview`; +export const SECURITY_ANALYTICS_OVERVIEW_PAGE_ID = `${SECURITY_ANALYTICS_USE_CASE_ID}_overview`; export const HOME_PAGE_ID = 'osd_homepage'; -export const SEARCH_OVERVIEW_ID = 'search_overview'; // section ids export enum SECTIONS { @@ -39,7 +49,7 @@ export enum ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS { } export enum SEARCH_OVERVIEW_CONTENT_AREAS { - DIFFERENT_SEARCH_TYPES = `${SEARCH_OVERVIEW_ID}/${SECTIONS.DIFFERENT_SEARCH_TYPES}`, - CONFIG_EVALUATE_SEARCH = `${SEARCH_OVERVIEW_ID}/${SECTIONS.CONFIG_EVALUATE_SEARCH}`, - GET_STARTED = `${SEARCH_OVERVIEW_ID}/${SECTIONS.GET_STARTED}`, + DIFFERENT_SEARCH_TYPES = `${SEARCH_OVERVIEW_PAGE_ID}/${SECTIONS.DIFFERENT_SEARCH_TYPES}`, + CONFIG_EVALUATE_SEARCH = `${SEARCH_OVERVIEW_PAGE_ID}/${SECTIONS.CONFIG_EVALUATE_SEARCH}`, + GET_STARTED = `${SEARCH_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, } From 9c16d09bd17eae124724ce49e323610b43c3f1b6 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Mon, 26 Aug 2024 13:54:37 +0800 Subject: [PATCH 20/20] add unit test Signed-off-by: Hailong Cui --- .../content_management/public/mocks.ts | 1 + .../components/home_list_card.test.tsx | 64 ++++++++++++++++++- .../sample_data/sample_data_card.test.tsx | 7 +- 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/plugins/content_management/public/mocks.ts b/src/plugins/content_management/public/mocks.ts index 8f99be090231..79581c8e03dd 100644 --- a/src/plugins/content_management/public/mocks.ts +++ b/src/plugins/content_management/public/mocks.ts @@ -9,6 +9,7 @@ const createStartContract = (): ContentManagementPluginStart => { return { registerContentProvider: jest.fn(), renderPage: jest.fn(), + updatePageSection: jest.fn(), }; }; diff --git a/src/plugins/home/public/application/components/home_list_card.test.tsx b/src/plugins/home/public/application/components/home_list_card.test.tsx index 8558c62727a4..f5916e4b74e7 100644 --- a/src/plugins/home/public/application/components/home_list_card.test.tsx +++ b/src/plugins/home/public/application/components/home_list_card.test.tsx @@ -6,7 +6,8 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { HomeListCard } from './home_list_card'; +import { HomeListCard, registerHomeListCardToPage } from './home_list_card'; +import { contentManagementPluginMocks } from '../../../../content_management/public'; describe('', () => { it('should render static content normally', async () => { @@ -60,3 +61,64 @@ it('should not show View All button when allLink is not provided', () => { const { queryByText } = render(); expect(queryByText('View all')).not.toBeInTheDocument(); }); + +describe('Register HomeListCardToPages', () => { + const registerContentProviderFn = jest.fn(); + const contentManagementStartMock = { + ...contentManagementPluginMocks.createStartContract(), + registerContentProvider: registerContentProviderFn, + }; + + it('register to use case overview page', () => { + registerHomeListCardToPage(contentManagementStartMock); + expect(contentManagementStartMock.registerContentProvider).toHaveBeenCalledTimes(4); + + let whatsNewCall = registerContentProviderFn.mock.calls[0]; + expect(whatsNewCall[0].getTargetArea()).toEqual('analytics_overview/service_cards'); + expect(whatsNewCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "whats_new", + "kind": "custom", + "order": 10, + "render": [Function], + "width": 24, + } + `); + + let learnOpenSearchCall = registerContentProviderFn.mock.calls[1]; + expect(learnOpenSearchCall[0].getTargetArea()).toEqual('analytics_overview/service_cards'); + expect(learnOpenSearchCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "learn_opensearch_new", + "kind": "custom", + "order": 20, + "render": [Function], + "width": 24, + } + `); + + whatsNewCall = registerContentProviderFn.mock.calls[2]; + expect(whatsNewCall[0].getTargetArea()).toEqual('all_overview/service_cards'); + expect(whatsNewCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "whats_new", + "kind": "custom", + "order": 30, + "render": [Function], + "width": undefined, + } + `); + + learnOpenSearchCall = registerContentProviderFn.mock.calls[3]; + expect(learnOpenSearchCall[0].getTargetArea()).toEqual('all_overview/service_cards'); + expect(learnOpenSearchCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "learn_opensearch_new", + "kind": "custom", + "order": 40, + "render": [Function], + "width": undefined, + } + `); + }); +}); diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx index f333743796df..44d7a4b6f007 100644 --- a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx @@ -4,17 +4,16 @@ */ import { registerSampleDataCard } from './sample_data_card'; -import { ContentManagementPluginStart } from '../../../../../../plugins/content_management/public'; import { coreMock } from '../../../../../../core/public/mocks'; +import { contentManagementPluginMocks } from '../../../../../content_management/public'; describe('Sample data card', () => { const coreStart = coreMock.createStart(); const registerContentProviderMock = jest.fn(); - const contentManagement: ContentManagementPluginStart = { + const contentManagement = { + ...contentManagementPluginMocks.createStartContract(), registerContentProvider: registerContentProviderMock, - renderPage: jest.fn(), - updatePageSection: jest.fn(), }; it('should call the getTargetArea function with the correct arguments', () => {