From 8d415c8a402c6ade95e41bba6eb3678f10515cc3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 30 Sep 2024 08:03:14 +0000 Subject: [PATCH] [Workspace] Fix fit&finish for workspace overview page (#8139) * fit&finish for workspace overview page Signed-off-by: Hailong Cui * Changeset file for PR #8139 created/updated * revert recent_items.tsx change Signed-off-by: Hailong Cui * use doclink service to build links Signed-off-by: Hailong Cui * remove commented urls Signed-off-by: Hailong Cui * update getting started card title size Signed-off-by: Hailong Cui * update getting started card title size Signed-off-by: Hailong Cui * recently updated assets Signed-off-by: Hailong Cui * update card title size Signed-off-by: Hailong Cui * Changeset file for PR #8139 created/updated * address review comments Signed-off-by: Hailong Cui * fix for search overview page Signed-off-by: Hailong Cui * wrap the card title Signed-off-by: Hailong Cui * make getting started card not collapseable Signed-off-by: Hailong Cui * udpate getting started card title size Signed-off-by: Hailong Cui * address review comments Signed-off-by: Hailong Cui * address review comments Signed-off-by: Hailong Cui --------- Signed-off-by: Hailong Cui Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> (cherry picked from commit 69ec2791e94c8fdbf75f4aed09b939280de120ef) Signed-off-by: github-actions[bot] --- changelogs/fragments/8139.yml | 2 + .../public/doc_links/doc_links_service.ts | 9 +- src/core/utils/default_nav_groups.ts | 6 +- .../advanced_settings.test.tsx.snap | 48 +++- .../card_container/card_embeddable.tsx | 2 +- .../card_container/card_list.test.tsx | 2 +- .../components/card_container/card_list.tsx | 6 +- .../public/components/section_render.tsx | 17 +- .../services/content_management/types.ts | 1 + .../dashboard_top_nav.test.tsx.snap | 36 ++- .../language_selector.test.tsx.snap | 12 +- .../public/application/components/_index.scss | 1 + .../components/home_list_card.test.tsx | 8 +- .../application/components/home_list_card.tsx | 73 ++--- .../sample_data/sample_data_card.test.tsx | 8 +- .../sample_data/sample_data_card.tsx | 8 +- .../usecase_overview/search_overview.scss | 3 + .../search_use_case_setup.test.tsx | 6 +- .../search_use_case_setup.tsx | 12 +- .../public/application/home_render.test.tsx | 83 +++--- .../home/public/application/home_render.tsx | 9 +- src/plugins/home/public/plugin.ts | 2 +- .../management_section/recent_work.test.tsx | 169 +++++++++++- .../public/management_section/recent_work.tsx | 253 +++++++++++++----- .../server/routes/find.ts | 1 + .../use_case_overview/get_started_cards.tsx | 24 +- .../use_case_overview/setup_overview.test.tsx | 12 +- .../use_case_overview/setup_overview.tsx | 4 + 28 files changed, 604 insertions(+), 213 deletions(-) create mode 100644 changelogs/fragments/8139.yml create mode 100644 src/plugins/home/public/application/components/usecase_overview/search_overview.scss diff --git a/changelogs/fragments/8139.yml b/changelogs/fragments/8139.yml new file mode 100644 index 000000000000..9f60fbf5195b --- /dev/null +++ b/changelogs/fragments/8139.yml @@ -0,0 +1,2 @@ +fix: +- Fix fit & finish for workspace overview getting started and assets section ([#8139](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8139)) \ No newline at end of file diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index edfb02f6c35c..c9a87d4247df 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -424,7 +424,13 @@ export class DocLinksService { }, visualize: { // https://opensearch.org/docs/latest/dashboards/visualize/viz-index/ - guide: `${OPENSEARCH_WEBSITE_DOCS}visualize/viz-index/`, + guide: `${OPENSEARCH_DASHBOARDS_VERSIONED_DOCS}visualize/viz-index/`, + }, + dashboards: { + // https://opensearch.org/docs/latest/dashboards/quickstart/ + quickStart: `${OPENSEARCH_DASHBOARDS_VERSIONED_DOCS}quickstart/`, + // https://opensearch.org/docs/latest/dashboards/dashboard/index/ + createDashboards: `${OPENSEARCH_DASHBOARDS_VERSIONED_DOCS}dashboard/index/`, }, management: { // https://opensearch.org/docs/latest/dashboards/management/advanced-settings/ @@ -826,6 +832,7 @@ export interface DocLinksStart { readonly s3DataSource: string; }; readonly visualize: Record; + readonly dashboards: Record; readonly management: Record; }; readonly noDocumentation: { diff --git a/src/core/utils/default_nav_groups.ts b/src/core/utils/default_nav_groups.ts index bbd38c81ffc5..76fedcf803ea 100644 --- a/src/core/utils/default_nav_groups.ts +++ b/src/core/utils/default_nav_groups.ts @@ -52,7 +52,7 @@ const defaultNavGroups = { defaultMessage: 'Observability', }), description: i18n.translate('core.ui.group.observability.description', { - defaultMessage: 'Gain visibility into your application and infrastructure', + defaultMessage: 'Gain visibility into your applications and infrastructure.', }), order: 4000, icon: 'wsObservability', @@ -63,7 +63,7 @@ const defaultNavGroups = { defaultMessage: 'Security Analytics', }), description: i18n.translate('core.ui.group.security.analytics.description', { - defaultMessage: 'Enhance your security posture with advanced analytics', + defaultMessage: 'Enhance your security posture with advanced analytics.', }), order: 5000, icon: 'wsSecurityAnalytics', @@ -86,7 +86,7 @@ const defaultNavGroups = { defaultMessage: 'Search', }), description: i18n.translate('core.ui.group.search.description', { - defaultMessage: 'Discover and query your data with ease', + defaultMessage: 'Discover and query your data with ease.', }), order: 6000, icon: 'wsSearch', diff --git a/src/plugins/advanced_settings/public/management_app/__snapshots__/advanced_settings.test.tsx.snap b/src/plugins/advanced_settings/public/management_app/__snapshots__/advanced_settings.test.tsx.snap index d487e1d9c8e9..ce59c66476ec 100644 --- a/src/plugins/advanced_settings/public/management_app/__snapshots__/advanced_settings.test.tsx.snap +++ b/src/plugins/advanced_settings/public/management_app/__snapshots__/advanced_settings.test.tsx.snap @@ -365,6 +365,10 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -400,7 +404,7 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, } @@ -998,6 +1002,10 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -1033,7 +1041,7 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, } @@ -1896,6 +1904,10 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -1931,7 +1943,7 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, } @@ -2291,6 +2303,10 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -2326,7 +2342,7 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, } @@ -2686,6 +2702,10 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -2721,7 +2741,7 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, } @@ -3081,6 +3101,10 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -3116,7 +3140,7 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, } @@ -3531,6 +3555,10 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -3566,7 +3594,7 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, } @@ -3928,6 +3956,10 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -3963,7 +3995,7 @@ exports[`AdvancedSettings should render normally when use updated UX 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, } 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 5708c2c7c4f7..358078d40d58 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 @@ -36,7 +36,7 @@ export class CardEmbeddable extends Embeddable { const cardProps: EuiCardProps = { ...this.input.cardProps, - title: (this.input?.getTitle?.() || this.input?.title) ?? '', + title: this.input?.getTitle?.() || this.input?.title || '', description: ( <>{this.input.description} diff --git a/src/plugins/content_management/public/components/card_container/card_list.test.tsx b/src/plugins/content_management/public/components/card_container/card_list.test.tsx index 262fbeb4a71f..bab1e0280d1e 100644 --- a/src/plugins/content_management/public/components/card_container/card_list.test.tsx +++ b/src/plugins/content_management/public/components/card_container/card_list.test.tsx @@ -4,7 +4,7 @@ */ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { render } from '@testing-library/react'; import { CardList } from './card_list'; import { CardContainer } from './card_container'; 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 2bbbd87c3a54..33773f34029f 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 @@ -42,7 +42,7 @@ const CardListInner = ({ embeddable, input, embeddableServices }: Props) => { {cards} @@ -65,14 +65,14 @@ const CardListInner = ({ embeddable, input, embeddableServices }: Props) => { if (input.grid && input.columns) { return ( - + {cards} ); } return ( - + {cards} ); diff --git a/src/plugins/content_management/public/components/section_render.tsx b/src/plugins/content_management/public/components/section_render.tsx index 746dbd92bb16..08eac7f92f88 100644 --- a/src/plugins/content_management/public/components/section_render.tsx +++ b/src/plugins/content_management/public/components/section_render.tsx @@ -62,24 +62,27 @@ const CardSection = ({ section, embeddable, contents$ }: Props) => { const factory = embeddable.getEmbeddableFactory(CARD_CONTAINER); if (section.kind === 'card' && factory && input) { + const isCardCollapsible = section.collapsible; return ( <> {section.title ? (

- setIsCardVisible(!isCardVisible)} - color="text" - aria-label={isCardVisible ? 'Show panel' : 'Hide panel'} - /> + {isCardCollapsible ? ( + setIsCardVisible(!isCardVisible)} + color="text" + aria-label={isCardVisible ? 'Show panel' : 'Hide panel'} + /> + ) : null} {section.title}

) : null} {isCardVisible && ( <> - + )} 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 94e69d348ef1..6d780e51767d 100644 --- a/src/plugins/content_management/public/services/content_management/types.ts +++ b/src/plugins/content_management/public/services/content_management/types.ts @@ -36,6 +36,7 @@ export type Section = id: string; order: number; title?: string; + collapsible?: boolean; input?: CardContainerExplicitInput; columns?: number; wrap?: boolean; diff --git a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap index 9003cc444c81..01c2616bf0ea 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap @@ -737,6 +737,10 @@ exports[`Dashboard top nav render in embed mode 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -772,7 +776,7 @@ exports[`Dashboard top nav render in embed mode 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, }, @@ -1798,6 +1802,10 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -1833,7 +1841,7 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, }, @@ -2859,6 +2867,10 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -2894,7 +2906,7 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, }, @@ -3920,6 +3932,10 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -3955,7 +3971,7 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, }, @@ -4981,6 +4997,10 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -5016,7 +5036,7 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, }, @@ -6042,6 +6062,10 @@ exports[`Dashboard top nav render with all components 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -6077,7 +6101,7 @@ exports[`Dashboard top nav render with all components 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, }, diff --git a/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap b/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap index fd8aa75f7344..8a7914a15d81 100644 --- a/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap +++ b/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap @@ -421,6 +421,10 @@ exports[`LanguageSelector should select DQL if language is kuery 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -456,7 +460,7 @@ exports[`LanguageSelector should select DQL if language is kuery 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, }, @@ -995,6 +999,10 @@ exports[`LanguageSelector should select lucene if language is lucene 1`] = ` }, "opensearchDashboards": Object { "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", + "dashboards": Object { + "createDashboards": "https://opensearch.org/docs/mocked-test-branch/dashboards/dashboard/index/", + "quickStart": "https://opensearch.org/docs/mocked-test-branch/dashboards/quickstart/", + }, "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", @@ -1030,7 +1038,7 @@ exports[`LanguageSelector should select lucene if language is lucene 1`] = ` }, "reporting": "https://opensearch.org/docs/mocked-test-branch/dashboards/reporting", "visualize": Object { - "guide": "https://opensearch.org/docs/mocked-test-branchvisualize/viz-index/", + "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/visualize/viz-index/", }, }, }, diff --git a/src/plugins/home/public/application/components/_index.scss b/src/plugins/home/public/application/components/_index.scss index 8370781134ea..ec56721c3f0e 100644 --- a/src/plugins/home/public/application/components/_index.scss +++ b/src/plugins/home/public/application/components/_index.scss @@ -13,3 +13,4 @@ @import "welcome"; @import "tutorial/tutorial"; @import "homepage/homepage"; +@import "usecase_overview/search_overview" 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 cbad31f15993..1492d82dc544 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 @@ -8,6 +8,8 @@ import { render } from '@testing-library/react'; import { HomeListCard, registerHomeListCardToPage } from './home_list_card'; import { contentManagementPluginMocks } from '../../../../content_management/public'; +import { EuiLink } from '@elastic/eui'; +import { docLinksServiceMock } from '../../../../../core/public/mocks'; describe('', () => { it('should render static content normally', async () => { @@ -38,7 +40,7 @@ it('should render View All button when allLink is provided', () => { description: 'Get started in minutes with OpenSearch Dashboards', }, ], - allLink: 'https://opensearch.org/docs/latest/', + allLink: View all, }; const { getByText } = render(); @@ -69,8 +71,10 @@ describe('Register HomeListCardToPages', () => { registerContentProvider: registerContentProviderFn, }; + const docLinkMock = docLinksServiceMock.createStartContract(); + it('register to use case overview page', () => { - registerHomeListCardToPage(contentManagementStartMock); + registerHomeListCardToPage(contentManagementStartMock, docLinkMock); expect(contentManagementStartMock.registerContentProvider).toHaveBeenCalledTimes(4); let whatsNewCall = registerContentProviderFn.mock.calls[0]; 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 fbc4b70dca08..745291dae6e7 100644 --- a/src/plugins/home/public/application/components/home_list_card.tsx +++ b/src/plugins/home/public/application/components/home_list_card.tsx @@ -17,48 +17,66 @@ import { EuiFlexItem, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; +import { DocLinksStart } from 'opensearch-dashboards/public'; 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', { - defaultMessage: 'Learn Opensearch', +export const getLearnOpenSearchConfig = (docLinks: DocLinksStart): Config => ({ + title: i18n.translate('home.card.learnOpenSearch.title', { + defaultMessage: 'OpenSearch Documentation', }), list: [ { label: 'Quickstart guide', - href: 'https://opensearch.org/docs/latest/dashboards/quickstart/', - description: 'Get started in minutes with OpenSearch Dashboards', + href: docLinks.links.opensearchDashboards.dashboards.quickStart, + description: 'Start using OpenSearch Dashboards in minutes.', }, { label: 'Building data visualizations', - href: 'https://opensearch.org/docs/latest/dashboards/visualize/viz-index/', + href: docLinks.links.opensearchDashboards.visualize.guide, description: 'Design interactive charts and graphs to unlock insights form your data.', }, { label: 'Creating dashboards', - href: 'https://opensearch.org/docs/latest/dashboards/dashboard/index/', - description: 'Build interactive dashboards to explore and analyze your data', + href: docLinks.links.opensearchDashboards.dashboards.createDashboards, + description: 'Build interactive dashboards to explore and analyze your data.', }, ], - allLink: 'https://opensearch.org/docs/latest/', -}; + allLink: ( + + + {i18n.translate('home.list.card.documentation', { + defaultMessage: 'Learn more in Documentation', + })} + + + ), +}); -export const WHATS_NEW_CONFIG = { - title: i18n.translate('homepage.card.whatsNew.title', { +export const getWhatsNewConfig = (docLinks: DocLinksStart): Config => ({ + title: i18n.translate('home.card.whatsNew.title', { defaultMessage: `What's New`, }), list: [ { label: 'Quickstart guide', - href: 'https://opensearch.org/docs/latest/dashboards/quickstart/', + href: docLinks.links.opensearchDashboards.dashboards.quickStart, description: 'Get started in minutes with OpenSearch Dashboards', }, ], -}; + allLink: ( + + + {i18n.translate('home.list.card.whatsnew', { + defaultMessage: 'View all on OpenSearch.org', + })} + + + ), +}); interface Config { title: string; @@ -67,7 +85,7 @@ interface Config { href: string; description: string; }>; - allLink?: string; + allLink?: React.JSX.Element; } export const HomeListCard = ({ config }: { config: Config }) => { @@ -105,17 +123,7 @@ export const HomeListCard = ({ config }: { config: Config }) => { )} - - {config.allLink ? ( - - - {i18n.translate('home.list.card.view_all', { - defaultMessage: 'View all', - })} - - - ) : null} - + {config.allLink}
@@ -153,11 +161,14 @@ export const registerHomeListCard = ( getTargetArea: () => target, }); }; -export const registerHomeListCardToPage = (contentManagement: ContentManagementPluginStart) => { +export const registerHomeListCardToPage = ( + contentManagement: ContentManagementPluginStart, + docLinks: DocLinksStart +) => { registerHomeListCard(contentManagement, { id: 'whats_new', order: 10, - config: WHATS_NEW_CONFIG, + config: getWhatsNewConfig(docLinks), target: ESSENTIAL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, width: 24, }); @@ -165,7 +176,7 @@ export const registerHomeListCardToPage = (contentManagement: ContentManagementP registerHomeListCard(contentManagement, { id: 'learn_opensearch_new', order: 20, - config: LEARN_OPENSEARCH_CONFIG, + config: getLearnOpenSearchConfig(docLinks), target: ESSENTIAL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, width: 24, }); @@ -173,14 +184,14 @@ export const registerHomeListCardToPage = (contentManagement: ContentManagementP registerHomeListCard(contentManagement, { id: 'whats_new', order: 30, - config: WHATS_NEW_CONFIG, + config: getWhatsNewConfig(docLinks), target: ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, }); registerHomeListCard(contentManagement, { id: 'learn_opensearch_new', order: 40, - config: LEARN_OPENSEARCH_CONFIG, + config: getLearnOpenSearchConfig(docLinks), target: ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, }); }; 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 03552b6444b2..6d3d3559605c 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 @@ -25,18 +25,20 @@ describe('Sample data card', () => { "cardProps": Object { "selectable": Object { "children": , "isSelected": false, "onClick": [Function], }, + "titleElement": "h4", + "titleSize": "s", }, - "description": "You can install sample data to experiment with OpenSearch Dashboards.", + "description": "Explore sample data before adding your own.", "id": "sample_data", "kind": "card", "order": 0, - "title": "Try openSearch", + "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 84e9191fac43..061f00335212 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,14 +27,16 @@ export const registerSampleDataCard = ( kind: 'card', order, description: i18n.translate('home.sampleData.card.description', { - defaultMessage: 'You can install sample data to experiment with OpenSearch Dashboards.', + defaultMessage: 'Explore sample data before adding your own.', }), title: i18n.translate('home.sampleData.card.title', { - defaultMessage: 'Try openSearch', + defaultMessage: 'Try OpenSearch', }), cardProps: { + titleElement: 'h4', + titleSize: 's', selectable: { - children: , + children: , isSelected: false, onClick: () => { // TODO change to a modal diff --git a/src/plugins/home/public/application/components/usecase_overview/search_overview.scss b/src/plugins/home/public/application/components/usecase_overview/search_overview.scss new file mode 100644 index 000000000000..a63120bd2889 --- /dev/null +++ b/src/plugins/home/public/application/components/usecase_overview/search_overview.scss @@ -0,0 +1,3 @@ +.searchIcon { + color: tint($euiLinkColor, 50%); +} diff --git a/src/plugins/home/public/application/components/usecase_overview/search_use_case_setup.test.tsx b/src/plugins/home/public/application/components/usecase_overview/search_use_case_setup.test.tsx index 3d622b44d046..9c5efee630c1 100644 --- a/src/plugins/home/public/application/components/usecase_overview/search_use_case_setup.test.tsx +++ b/src/plugins/home/public/application/components/usecase_overview/search_use_case_setup.test.tsx @@ -75,6 +75,8 @@ describe('Search use case setup', () => { "isSelected": false, "onClick": [Function], }, + "titleElement": "h4", + "titleSize": "s", }, "description": "You can run a search using REST API or language client. For experimentation, you can also run queries interactively.", "id": "access_search_functionality", @@ -95,13 +97,15 @@ describe('Search use case setup', () => { > View Documentation , "layout": "horizontal", + "titleElement": "h3", + "titleSize": "s", }, "description": "Lexical or keyword search matches documents based on exact words or phrases. Search the text using human-friendly query string query syntax or create complex, customizable queries using Query DSL—the OpenSearch query language.", "getIcon": [Function], diff --git a/src/plugins/home/public/application/components/usecase_overview/search_use_case_setup.tsx b/src/plugins/home/public/application/components/usecase_overview/search_use_case_setup.tsx index d3a7abf8986c..96e0b159c595 100644 --- a/src/plugins/home/public/application/components/usecase_overview/search_use_case_setup.tsx +++ b/src/plugins/home/public/application/components/usecase_overview/search_use_case_setup.tsx @@ -102,6 +102,8 @@ export const registerContentToSearchUseCasePage = ( title: card.title, description: card.description, cardProps: { + titleElement: 'h4', + titleSize: 's', selectable: { onClick: () => { window.open(card.documentURL, '_blank'); @@ -115,7 +117,7 @@ export const registerContentToSearchUseCasePage = ( }); }); - const searchIcon = ; + const searchIcon = ; const searchTypeCards = [ { @@ -133,7 +135,7 @@ export const registerContentToSearchUseCasePage = ( View Documentation @@ -194,7 +196,7 @@ export const registerContentToSearchUseCasePage = ( 'home.searchOverview.searchTypes.neuralSparseSearch.description', { defaultMessage: - 'Neural sparse search combines many of the advantages of Lexical and semantic search.', + 'Neural sparse search combines many of the advantages of lexical and semantic search.', } ), icon: searchIcon, @@ -216,7 +218,7 @@ export const registerContentToSearchUseCasePage = ( }), description: i18n.translate('home.searchOverview.searchTypes.hybridSearch.description', { defaultMessage: - 'For many uses, lexical and semantic search are complementary: Lexical search performs better on highly specific queries, while semantic search performs better on broader queries. Hybrid search runs both search types and combines the results, generally producing better results than either one separately.', + 'For many uses, lexical and semantic search are complementary: lexical search performs better on highly specific queries, while semantic search performs better on broader queries. Hybrid search runs both search types and combines the results, generally producing better results than either one separately.', }), icon: searchIcon, footer: ( @@ -244,6 +246,8 @@ export const registerContentToSearchUseCasePage = ( cardProps: { children:
{card.footer}
, layout: 'horizontal', + titleElement: 'h3', + titleSize: 's', }, }), getTargetArea: () => SEARCH_OVERVIEW_CONTENT_AREAS.DIFFERENT_SEARCH_TYPES, diff --git a/src/plugins/home/public/application/home_render.test.tsx b/src/plugins/home/public/application/home_render.test.tsx index 34a5d690b44b..63cd57b3915d 100644 --- a/src/plugins/home/public/application/home_render.test.tsx +++ b/src/plugins/home/public/application/home_render.test.tsx @@ -14,9 +14,10 @@ import { contentManagementPluginMocks } from '../../../../plugins/content_manage import { registerUseCaseCard } from './components/use_case_card'; import { initHome } from './home_render'; +import { coreMock } from '../../../../core/public/mocks'; import { - WHATS_NEW_CONFIG, - LEARN_OPENSEARCH_CONFIG, + getLearnOpenSearchConfig, + getWhatsNewConfig, registerHomeListCard, } from './components/home_list_card'; @@ -24,9 +25,15 @@ jest.mock('./components/use_case_card', () => ({ registerUseCaseCard: jest.fn(), })); -jest.mock('./components/home_list_card', () => ({ - registerHomeListCard: jest.fn(), -})); +jest.mock('./components/home_list_card', () => { + const originalModule = jest.requireActual('./components/home_list_card'); + return { + ...originalModule, + registerHomeListCard: jest.fn(), + getWhatsNewConfig: jest.fn(() => {}), + getLeanOpenSearchConfig: jest.fn(() => {}), + }; +}); describe('initHome', () => { const registerContentProviderFn = jest.fn(); @@ -39,20 +46,20 @@ describe('initHome', () => { jest.clearAllMocks(); }); - it('should register use case cards when workspace is enabled', () => { - const coreMock = { - createStart: jest.fn(() => ({ - application: { - capabilities: { - workspaces: { - enabled: false, - }, + it('should register use case cards when workspace is disabled', () => { + const core = { + ...coreMock.createStart(), + application: { + ...coreMock.createStart().application, + capabilities: { + ...coreMock.createStart().application.capabilities, + workspaces: { + enabled: false, }, - navigateToApp: jest.fn(), }, - })), + navigateToApp: jest.fn(), + }, }; - const core = coreMock.createStart(); initHome(contentManagementStartMock, core); @@ -89,36 +96,38 @@ describe('initHome', () => { }); }); - it('should not register use case cards when workspace is disabled', () => { - const coreMock = { - createStart: jest.fn(() => ({ - application: { - capabilities: { - workspaces: { - enabled: true, - }, + it('should not register use case cards when workspace is enabled', () => { + const core = { + ...coreMock.createStart(), + application: { + ...coreMock.createStart().application, + capabilities: { + ...coreMock.createStart().application.capabilities, + workspaces: { + enabled: true, }, }, - })), + navigateToApp: jest.fn(), + }, }; - const core = coreMock.createStart(); initHome(contentManagementStartMock, core); expect(registerUseCaseCard).not.toHaveBeenCalled(); }); it('should register home list cards correctly', () => { - const coreMock = { - createStart: jest.fn(() => ({ - application: { - capabilities: { - workspaces: { - enabled: false, - }, + const core = { + ...coreMock.createStart(), + application: { + ...coreMock.createStart().application, + capabilities: { + ...coreMock.createStart().application.capabilities, + workspaces: { + enabled: false, }, }, - })), + navigateToApp: jest.fn(), + }, }; - const core = coreMock.createStart(); initHome(contentManagementStartMock, core); expect(registerHomeListCard).toHaveBeenCalledTimes(2); @@ -126,7 +135,7 @@ describe('initHome', () => { expect(registerHomeListCard).toHaveBeenCalledWith(contentManagementStartMock, { id: 'whats_new', order: 10, - config: WHATS_NEW_CONFIG, + config: getWhatsNewConfig(core.docLinks), target: HOME_CONTENT_AREAS.SERVICE_CARDS, width: 16, }); @@ -134,7 +143,7 @@ describe('initHome', () => { expect(registerHomeListCard).toHaveBeenCalledWith(contentManagementStartMock, { id: 'learn_opensearch_new', order: 11, - config: LEARN_OPENSEARCH_CONFIG, + config: getLearnOpenSearchConfig(core.docLinks), target: HOME_CONTENT_AREAS.SERVICE_CARDS, width: 16, }); diff --git a/src/plugins/home/public/application/home_render.tsx b/src/plugins/home/public/application/home_render.tsx index f22f3560205c..d4d247ec1652 100644 --- a/src/plugins/home/public/application/home_render.tsx +++ b/src/plugins/home/public/application/home_render.tsx @@ -17,8 +17,8 @@ import { SECURITY_ANALYTICS_OVERVIEW_PAGE_ID, } from '../../../../plugins/content_management/public'; import { - WHATS_NEW_CONFIG, - LEARN_OPENSEARCH_CONFIG, + getWhatsNewConfig, + getLearnOpenSearchConfig, registerHomeListCard, } from './components/home_list_card'; @@ -58,6 +58,7 @@ export const setupHome = (contentManagement: ContentManagementPluginSetup) => { order: 1000, title: "Get started with OpenSearch's powerful features", kind: 'card', + collapsible: true, }, ], }); @@ -92,7 +93,7 @@ export const initHome = (contentManagement: ContentManagementPluginStart, core: registerHomeListCard(contentManagement, { id: 'whats_new', order: 10, - config: WHATS_NEW_CONFIG, + config: getWhatsNewConfig(core.docLinks), target: HOME_CONTENT_AREAS.SERVICE_CARDS, width: 16, }); @@ -100,7 +101,7 @@ export const initHome = (contentManagement: ContentManagementPluginStart, core: registerHomeListCard(contentManagement, { id: 'learn_opensearch_new', order: 11, - config: LEARN_OPENSEARCH_CONFIG, + config: getLearnOpenSearchConfig(core.docLinks), target: HOME_CONTENT_AREAS.SERVICE_CARDS, width: 16, }); diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index 7ede9a32ecdb..744cffadf630 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -276,7 +276,7 @@ export class HomePublicPlugin registerContentToSearchUseCasePage(contentManagement, core); // register what's new learn opensearch card to use case overview page - registerHomeListCardToPage(contentManagement); + registerHomeListCardToPage(contentManagement, core.docLinks); this.featuresCatalogueRegistry.start({ capabilities }); this.sectionTypeService.start({ core, data }); diff --git a/src/plugins/saved_objects_management/public/management_section/recent_work.test.tsx b/src/plugins/saved_objects_management/public/management_section/recent_work.test.tsx index 4992a0247b09..fe5a12ad7791 100644 --- a/src/plugins/saved_objects_management/public/management_section/recent_work.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/recent_work.test.tsx @@ -5,7 +5,7 @@ import React from 'react'; import { BehaviorSubject } from 'rxjs'; -import { fireEvent, render } from '@testing-library/react'; +import { act, fireEvent, render, waitFor } from '@testing-library/react'; import { RecentWork } from './recent_work'; import { coreMock } from '../../../../core/public/mocks'; import { ChromeRecentlyAccessedHistoryItem } from 'opensearch-dashboards/public'; @@ -19,17 +19,27 @@ const mockedRecentItems: ChromeRecentlyAccessedHistoryItem[] = [ id: 'visualize', meta: { type: 'visualize', + lastAccessedTime: 1726648949036, }, + workspaceId: 'foo', }, { link: '/app/dashboard', label: 'dashboard', id: 'dashboard-in-workspace', - workspaceId: 'workspace-id', + workspaceId: 'foo', meta: { type: 'dashboard', + lastAccessedTime: 1726648948036, }, }, + { + link: '/app/index-pattern', + label: 'My Index pattern', + id: 'index-pattern', + workspaceId: 'bar', + meta: {}, + }, ]; const savedObjectsFromServer: SavedObjectWithMetadata[] = [ @@ -39,7 +49,14 @@ const savedObjectsFromServer: SavedObjectWithMetadata[] = [ attributes: {}, references: [], updated_at: '2024-07-20T00:00:00.000Z', - meta: {}, + meta: { + title: 'My Visualize', + inAppUrl: { + path: '/app/visualize#/visualize/visualize', + uiCapabilitiesPath: 'visualize.show', + }, + }, + workspaces: ['foo'], }, { type: 'dashboard', @@ -47,24 +64,86 @@ const savedObjectsFromServer: SavedObjectWithMetadata[] = [ attributes: {}, references: [], updated_at: '2024-07-20T00:00:01.000Z', - meta: {}, + meta: { + title: 'My Dashboard', + inAppUrl: { + path: '/app/dashboards#/dashboard-in-workspace', + uiCapabilitiesPath: 'dashboard.show', + }, + }, + workspaces: ['foo'], + }, + { + type: 'index-pattern', + id: 'index-pattern', + attributes: {}, + references: [], + updated_at: '2024-07-20T00:00:01.000Z', + meta: { + title: 'My Index pattern', + inAppUrl: { + path: '/app/home#/index-pattern/index-pattern', + uiCapabilitiesPath: 'indexPattern.show', + }, + }, + workspaces: ['bar'], + }, +]; + +const recentlyUpdateObjects = { + savedObjects: [ + { + type: 'search', + id: 'search-in-workspace', + attributes: {}, + references: [], + updated_at: '2024-07-20T00:00:01.000Z', + meta: { + title: 'My Search', + inAppUrl: { + path: '/app/search#/search-in-workspace', + uiCapabilitiesPath: 'search.show', + }, + }, + workspaces: ['foo'], + }, + ], +}; + +const workspaceList = [ + { + id: 'foo', + name: 'foo Workspace', }, ]; +const currentWorkspace = workspaceList[0]; + const getStartMockForRecentWork = () => { const coreStartMock = coreMock.createStart(); coreStartMock.chrome.recentlyAccessed.get$.mockReturnValue(new BehaviorSubject([])); coreStartMock.chrome.navLinks.getNavLinks$.mockReturnValue(new BehaviorSubject([])); + coreStartMock.workspaces.workspaceList$.next(workspaceList); + coreStartMock.workspaces.currentWorkspace$.next(currentWorkspace); return coreStartMock; }; +jest.mock('../lib', () => { + const originalModule = jest.requireActual('../lib'); + + return { + ...originalModule, + findObjects: jest.fn(() => recentlyUpdateObjects), + }; +}); + describe('', () => { - it('render with emty recent work', async () => { + it('render with empty recent work', async () => { const { findByText } = render(); - await findByText('No assets found'); + await findByText('No assets to display'); }); - it('render with recent works', async () => { + it('render with recent works - recently viewed', async () => { const coreStartMock = getStartMockForRecentWork(); coreStartMock.http.get.mockImplementation((url) => { if (typeof url === 'string') { @@ -82,18 +161,82 @@ describe('', () => { new BehaviorSubject(mockedRecentItems) ); - const { findAllByTestId, getByTestId } = render(); + const { findAllByTestId, queryByText } = render(); const allCards = await findAllByTestId('recentlyCard'); expect(allCards.length).toBe(2); expect(allCards[0].querySelector('.euiCard__titleAnchor')?.textContent).toEqual( mockedRecentItems[0].label.charAt(0).toUpperCase() + mockedRecentItems[0].label.slice(1) ); + // bar workspace item will not show + expect(queryByText('My Index pattern')).not.toBeInTheDocument(); + }); + + it('render with recent works with workspace enabled', async () => { + const coreStartMock = getStartMockForRecentWork(); + // no current workspace + coreStartMock.workspaces.currentWorkspace$.next(null); + coreStartMock.http.get.mockImplementation((url) => { + if (typeof url === 'string') { + if ((url as string).includes(mockedRecentItems[0].id)) { + return Promise.resolve(savedObjectsFromServer[0]); + } else { + return Promise.resolve(savedObjectsFromServer[1]); + } + } - // click the filter button - fireEvent.click(getByTestId('filterButton-Recently%20updated')); + return Promise.reject({}); + }); + + coreStartMock.chrome.recentlyAccessed.get$.mockReturnValue( + new BehaviorSubject(mockedRecentItems) + ); + + const { findAllByTestId, queryAllByText } = render( + + ); + const allCards = await findAllByTestId('recentlyCard'); + expect(allCards.length).toBe(2); + + // workspace name will display + expect(queryAllByText('foo Workspace')).toHaveLength(2); + }); + + it('render with recent works - recently updated', async () => { + const coreStartMock = getStartMockForRecentWork(); + coreStartMock.http.get.mockImplementation((url) => { + if (typeof url === 'string') { + if ((url as string).includes(mockedRecentItems[0].id)) { + return Promise.resolve(savedObjectsFromServer[0]); + } else { + return Promise.resolve(savedObjectsFromServer[1]); + } + } + + return Promise.reject({}); + }); + + coreStartMock.chrome.recentlyAccessed.get$.mockReturnValue( + new BehaviorSubject(mockedRecentItems) + ); + + const { findAllByTestId, getByTestId, queryByText } = render( + + ); + const allCards = await findAllByTestId('recentlyCard'); + expect(allCards.length).toBe(2); + + // click the recently updated filter + act(() => { + fireEvent.click(getByTestId('filterButton-Recently%20updated')); + }); + + await waitFor(() => expect(queryByText('Search')).toBeInTheDocument()); const allCardsAfterSort = await findAllByTestId('recentlyCard'); - expect(allCardsAfterSort[0].querySelector('.euiCard__titleAnchor')?.textContent).toEqual( - mockedRecentItems[1].label.charAt(0).toUpperCase() + mockedRecentItems[1].label.slice(1) + expect(allCardsAfterSort[0].querySelector('.euiCard__titleAnchor')?.href).toEqual( + 'http://localhost/w/foo/app/search#/search-in-workspace' + ); + expect(allCardsAfterSort[0].querySelector('.euiCard__description')?.textContent).toEqual( + 'My Search' ); }); @@ -102,7 +245,7 @@ describe('', () => { expect(getByText('View all')).toBeInTheDocument(); }); - it('shoule be able to be linked to the expected page when clicking View all button', () => { + it('should be able to be linked to the expected page when clicking View all button', () => { const coreStartMock = getStartMockForRecentWork(); const { getByText } = render(); const mockedViewAllButton = getByText('View all'); diff --git a/src/plugins/saved_objects_management/public/management_section/recent_work.tsx b/src/plugins/saved_objects_management/public/management_section/recent_work.tsx index 88cdfc142af4..917c4a4f7b25 100644 --- a/src/plugins/saved_objects_management/public/management_section/recent_work.tsx +++ b/src/plugins/saved_objects_management/public/management_section/recent_work.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useMemo, useState, useEffect, useRef } from 'react'; +import React, { useMemo, useState, useEffect, useRef, useCallback } from 'react'; import moment from 'moment'; import { EuiFlexItem, @@ -21,17 +21,21 @@ import { EuiSpacer, EuiText, EuiTitle, + EuiLoadingLogo, + EuiSmallButton, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { ChromeRecentlyAccessedHistoryItem, CoreStart, SavedObject, + SavedObjectsFindOptions, } from 'opensearch-dashboards/public'; import { useObservable } from 'react-use'; import { SavedObjectWithMetadata } from 'src/plugins/saved_objects_management/common'; +import { formatUrlWithWorkspaceId } from '../../../../core/public/utils'; import { APP_ID } from '../plugin'; -import { createRecentNavLink } from '../../../../core/public'; +import { findObjects } from '../lib'; const allOption = i18n.translate('savedObjectsManagement.recentWorkSection.all.items', { defaultMessage: 'All items', @@ -56,7 +60,7 @@ function sortBy(key: KeyOf) { return (a: T, b: T): number => (a[key] > b[key] ? -1 : b[key] > a[key] ? 1 : 0); } -type DetailedRecentlyAccessedItem = ChromeRecentlyAccessedHistoryItem & +type DetailedRecentlyAssetsItem = Partial & SavedObjectWithMetadata & ChromeRecentlyAccessedHistoryItem['meta'] & { updatedAt: number; @@ -75,15 +79,18 @@ const bulkGetDetail = ( obj.type )}/${encodeURIComponent(obj.id)}` ) - .catch((error) => ({ - id: obj.id, - type: obj.type, - error, - attributes: {}, - references: [], - meta: {}, - updated_at: '', - })) + .catch( + (error) => + ({ + id: obj.id, + type: obj.type, + error, + attributes: {}, + references: [], + meta: {}, + updated_at: '', + } as SavedObjectWithMetadata) + ) ) ); }; @@ -97,11 +104,15 @@ export const RecentWork = (props: { core: CoreStart; workspaceEnabled?: boolean const recently$Ref = useRef(core.chrome.recentlyAccessed.get$()); const recentAccessed = useObservable(recently$Ref.current, []); const workspaceList = useObservable(core.workspaces.workspaceList$, []); + const currentWorkspace = useObservable(core.workspaces.currentWorkspace$, null); const [selectedType, setSelectedType] = useState(allOption); const [selectedSort, setSelectedSort] = useState(recentlyViewed); - const [detailedSavedObjects, setDetailedSavedObjects] = useState( + const [detailedSavedObjects, setDetailedSavedObjects] = useState( [] ); + const [isLoading, setIsLoading] = useState(false); + + const useUpdatedUX = core.chrome.navGroup.getNavGroupEnabled(); const allOptions = useMemo(() => { const options: string[] = [allOption]; @@ -115,51 +126,145 @@ export const RecentWork = (props: { core: CoreStart; workspaceEnabled?: boolean return options.map((option: string) => ({ label: option, value: option })); }, [detailedSavedObjects]); - const capitalTheFirstLetter = function (recentAccessItem: DetailedRecentlyAccessedItem) { - return recentAccessItem.type.charAt(0).toUpperCase() + recentAccessItem.type.slice(1); + const capitalTheFirstLetter = function (str: string) { + return str ? str.charAt(0).toUpperCase() + str.slice(1) : ''; }; const itemsForDisplay = useMemo(() => { - const sortedResult = [...detailedSavedObjects] - .filter((item) => !item.error) - .sort(sortBy(sortKeyMap[selectedSort])); - return sortedResult.filter((item: SavedObject & ChromeRecentlyAccessedHistoryItem) => { + return [...detailedSavedObjects].filter((item) => { + if (item.error) return false; if (selectedType === allOption) return true; return item.type === selectedType; }); - }, [detailedSavedObjects, selectedSort, selectedType]); - - useEffect(() => { - const savedObjects = recentAccessed - .filter((item) => item.meta?.type) - .map((item) => ({ - type: item.meta?.type || '', - id: item.id, - })); + }, [detailedSavedObjects, selectedType]); - if (savedObjects.length) { - bulkGetDetail(savedObjects, core.http).then((res) => { - const formatDetailedSavedObjects = res.map((obj) => { - const recentAccessItem = recentAccessed.find( - (item) => item.id === obj.id - ) as ChromeRecentlyAccessedHistoryItem; + const constructInAppUrl = useCallback( + (object: SavedObjectWithMetadata) => { + const { path = '' } = object.meta.inAppUrl || {}; + let finalPath = path; + // index pattern has been move out of dashboard management to be a standalone application, + // the path changed from `/app/management/opensearch-dashboards/indexPatterns` to `/app/indexPatterns` + if (useUpdatedUX && finalPath) { + finalPath = finalPath.replace(/^\/app\/management\/opensearch-dashboards/, '/app'); + } + const basePath = core.http.basePath; + let inAppUrl = basePath.prepend(finalPath); + if (object.workspaces?.length) { + if (currentWorkspace) { + inAppUrl = formatUrlWithWorkspaceId(finalPath, currentWorkspace.id, basePath); + } else { + const workspace = workspaceList.find((item) => object.workspaces?.includes(item.id)); + if (workspace) { + inAppUrl = formatUrlWithWorkspaceId(finalPath, workspace.id, basePath); + } + } + } + return inAppUrl; + }, + [core.http.basePath, currentWorkspace, useUpdatedUX, workspaceList] + ); - const findWorkspace = workspaceList.find( - (workspace) => workspace.id === recentAccessItem.workspaceId + const getRecentlyUpdated = useCallback(async () => { + try { + const allowedTypes = [ + 'dashboard', + 'visualization', + 'search', + 'query', + 'index-pattern', + 'visualization-visbuilder', + ]; + const findOptions: SavedObjectsFindOptions = { + type: allowedTypes, + sortField: 'updated_at', + sortOrder: 'desc', + workspaces: currentWorkspace ? [currentWorkspace.id] : undefined, + page: 1, + }; + const res = await findObjects(core.http, findOptions); + const savedObjects = res.savedObjects + .map((obj) => { + const findWorkspace = workspaceList.find((workspace) => + obj.workspaces?.includes(workspace.id) ); return { - ...recentAccessItem, ...obj, - ...recentAccessItem.meta, updatedAt: moment(obj?.updated_at).valueOf(), + lastAccessedTime: moment(obj?.updated_at).valueOf(), workspaceName: findWorkspace?.name, + label: obj.meta.title, + link: constructInAppUrl(obj), }; + }) + .sort(sortBy(sortKeyMap[recentlyUpdated])); + setDetailedSavedObjects(savedObjects); + } finally { + setIsLoading(false); + } + }, [constructInAppUrl, core.http, currentWorkspace, workspaceList]); + + const getRecentAccessed = useCallback(() => { + setIsLoading(true); + try { + const savedObjects = recentAccessed + .filter( + (item) => + item.meta?.type && + (!currentWorkspace || (currentWorkspace && item.workspaceId === currentWorkspace.id)) + ) + .map((item) => ({ + type: item.meta?.type || '', + id: item.id, + })); + + if (savedObjects.length) { + bulkGetDetail(savedObjects, core.http).then((res) => { + const formatDetailedSavedObjects = res + .map((obj) => { + const recentAccessItem = recentAccessed.find( + (item) => item.id === obj.id + ) as ChromeRecentlyAccessedHistoryItem; + + const findWorkspace = workspaceList.find( + (workspace) => workspace.id === recentAccessItem.workspaceId + ); + + const { link, label, workspaceId } = recentAccessItem; + const basePath = core.http.basePath; + + const href = formatUrlWithWorkspaceId(link, workspaceId || '', basePath); + + return { + ...recentAccessItem, + ...obj, + ...recentAccessItem.meta, + workspaceName: findWorkspace?.name, + updatedAt: moment(obj?.updated_at).valueOf(), + link: href, + label: label || obj.meta.title, + }; + }) + .sort(sortBy(sortKeyMap[recentlyViewed])); + setDetailedSavedObjects(formatDetailedSavedObjects); }); - setDetailedSavedObjects(formatDetailedSavedObjects); - }); + } else { + setDetailedSavedObjects([]); + } + } finally { + setIsLoading(false); } - }, [core.savedObjects.client, recentAccessed, core.http, workspaceList]); + }, [core.http, currentWorkspace, recentAccessed, workspaceList]); + + useEffect(() => { + // reset to allOption + setSelectedType(allOption); + if (selectedSort === recentlyUpdated) { + getRecentlyUpdated(); + } else { + getRecentAccessed(); + } + }, [getRecentlyUpdated, getRecentAccessed, selectedSort]); return ( @@ -181,7 +286,7 @@ export const RecentWork = (props: { core: CoreStart; workspaceEnabled?: boolean position="right" content={i18n.translate('savedObjectsManagement.recentWorkSection.assetsInfo', { defaultMessage: - 'Dashboards, visualizations, saved queries, and other assets within your Worksapces.', + 'Dashboards, visualizations, saved queries, and other assets within your Workspaces.', })} data-test-subj="assetsTooltip" > @@ -227,14 +332,6 @@ export const RecentWork = (props: { core: CoreStart; workspaceEnabled?: boolean const recentAccessItem = itemsForDisplay[itemIndexInRow]; let content = null; if (recentAccessItem) { - const navLinks = core.chrome.navLinks.getAll(); - const recentNavLink = createRecentNavLink( - recentAccessItem, - navLinks, - core.http.basePath, - core.application.navigateToUrl - ); - content = ( - {capitalTheFirstLetter(recentAccessItem)} + {capitalTheFirstLetter(recentAccessItem.type)} } data-test-subj="recentlyCard" - description={

{recentAccessItem.label}

} + description={

{recentAccessItem.label}

} textAlign="left" - href={recentNavLink.href} + href={recentAccessItem.link} footer={
- {workspaceEnabled && ( + {workspaceEnabled && !currentWorkspace && ( @@ -317,7 +415,6 @@ export const RecentWork = (props: { core: CoreStart; workspaceEnabled?: boolean )} } - onClick={recentNavLink.onClick} /> ); } @@ -326,25 +423,55 @@ export const RecentWork = (props: { core: CoreStart; workspaceEnabled?: boolean ); })} + ) : isLoading ? ( + } + title={

Loading Assets

} + /> ) : ( } title={ -

+

{i18n.translate('savedObjectsManagement.recentWorkSection.empty.title', { - defaultMessage: 'No assets found', + defaultMessage: 'No assets to display', })} -

+ + } + body={ + + + + {i18n.translate('savedObjectsManagement.recentWorkSection.empty.body', { + defaultMessage: 'The recent assets will appear here.', + })} + + + + + {i18n.translate('savedObjectsManagement.recentWorkSection.empty.manageAssets', { + defaultMessage: 'Manage assets', + })} + + + } - body={i18n.translate('savedObjectsManagement.recentWorkSection.empty.body', { - defaultMessage: "Assets you've recently viewed or updated will appear here.", - })} /> )} core.application.navigateToApp(APP_ID)}> - {i18n.translate('home.list.card.view_all', { + {i18n.translate('savedObjectsManagement.recentWorkSection.view_all', { defaultMessage: 'View all', })} diff --git a/src/plugins/saved_objects_management/server/routes/find.ts b/src/plugins/saved_objects_management/server/routes/find.ts index 3f77457bc245..8c8c43477d16 100644 --- a/src/plugins/saved_objects_management/server/routes/find.ts +++ b/src/plugins/saved_objects_management/server/routes/find.ts @@ -55,6 +55,7 @@ export const registerFindRoute = ( defaultValue: 'OR', }), sortField: schema.maybe(schema.string()), + sortOrder: schema.maybe(schema.string()), hasReference: schema.maybe( schema.object({ type: schema.string(), 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 index f4edb5466215..f9ff96efd0f0 100644 --- 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 @@ -24,13 +24,13 @@ export const getStartedCards: GetStartCard[] = [ { id: 'get_start_discover', title: i18n.translate('workspace.essential_overview.discover.card.title', { - defaultMessage: 'Discover insights', + defaultMessage: 'Explore data', }), description: i18n.translate('workspace.essential_overview.discover.card.description', { - defaultMessage: 'Explore data interactively to uncover insights.', + defaultMessage: 'Explore data to uncover insights.', }), footer: ( - + ), navigateAppId: DISCOVER_APP_ID, order: 20, @@ -41,14 +41,10 @@ export const getStartedCards: GetStartCard[] = [ defaultMessage: 'Visualize data', }), description: i18n.translate('workspace.essential_overview.visualize.card.description', { - defaultMessage: - 'Unlock insightful data exploration with visualization and aggregation tools.', + defaultMessage: 'Gain deeper insights by visualizing and aggregating your data.', }), footer: ( - + ), navigateAppId: VISUALIZE_APP_ID, order: 30, @@ -56,16 +52,14 @@ export const getStartedCards: GetStartCard[] = [ { id: 'get_start_dashboards', title: i18n.translate('workspace.essential_overview.dashboards.card.title', { - defaultMessage: 'View the big picture', + defaultMessage: 'Explore your data at a glance', }), description: i18n.translate('workspace.essential_overview.dashboards.card.description', { - defaultMessage: 'Gain clarity and visibility with dynamic data visualization tools.', + defaultMessage: + 'Monitor and understand your data connections using dynamic data visualization tools.', }), footer: ( - + ), navigateAppId: DASHBOARDS_APP_ID, order: 40, 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 e1f47c9756d1..a895534e47a9 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 @@ -77,18 +77,20 @@ describe('Setup use case overview', () => { "cardProps": Object { "selectable": Object { "children": , "isSelected": false, "onClick": [Function], }, + "titleElement": "h4", + "titleSize": "s", }, - "description": "Explore data interactively to uncover insights.", + "description": "Explore data to uncover insights.", "id": "get_start_discover", "kind": "card", "order": 20, - "title": "Discover insights", + "title": "Explore data", } `); }); @@ -136,8 +138,10 @@ describe('Setup use case overview', () => { Object { "cardProps": Object { "layout": "horizontal", + "titleElement": "h4", + "titleSize": "s", }, - "description": "Gain visibility into your application and infrastructure", + "description": "Gain visibility into your applications and infrastructure.", "getIcon": [Function], "id": "observability", "kind": "card", 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 3d4436895b9c..5688e1108c31 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 @@ -77,6 +77,8 @@ export const registerEssentialOverviewContent = ( description: card.description, title: card.title, cardProps: { + titleElement: 'h4', + titleSize: 's', selectable: { onClick: () => { core.application.navigateToApp(card.navigateAppId); @@ -143,6 +145,8 @@ export const registerAnalyticsAllOverviewContent = ( description: card.description, title: card.title, cardProps: { + titleElement: 'h4', + titleSize: 's', layout: 'horizontal', }, onClick: async () => {