diff --git a/changelogs/fragments/7744.yml b/changelogs/fragments/7744.yml new file mode 100644 index 000000000000..a9af55e1c43b --- /dev/null +++ b/changelogs/fragments/7744.yml @@ -0,0 +1,2 @@ +refactor: +- Update page header for settings, objects and index pattern page ([#7744](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7744)) \ No newline at end of file diff --git a/src/plugins/advanced_settings/opensearch_dashboards.json b/src/plugins/advanced_settings/opensearch_dashboards.json index 609d7192727d..97848475efca 100644 --- a/src/plugins/advanced_settings/opensearch_dashboards.json +++ b/src/plugins/advanced_settings/opensearch_dashboards.json @@ -3,7 +3,7 @@ "version": "opensearchDashboards", "server": true, "ui": true, - "requiredPlugins": ["management"], + "requiredPlugins": ["management","navigation"], "optionalPlugins": ["home"], "requiredBundles": ["opensearchDashboardsReact", "home"] } 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 new file mode 100644 index 000000000000..5e6ba8097fcb --- /dev/null +++ b/src/plugins/advanced_settings/public/management_app/__snapshots__/advanced_settings.test.tsx.snap @@ -0,0 +1,4125 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AdvancedSettings should render normally when use updated UX 1`] = ` + +
+ , + }, + ] + } + setMountPoint={[MockFunction]} + /> + + search + + +
+ + + +
+ +
+
+
+
+
+ +
+ +
+ +
+ +
+ +
+

+ Category +

+
+
+ +
+ + + + + + , + "settingsCount": 8, + } + } + > + Search terms are hiding 8 settings + + + + + +
+
+
+
+
+
+ +
+ + + field + + + field + + + field + + + field + +
+ +
+ + +
+ + +
+ +
+ +
+ +
+ +
+

+ Opensearch +

+
+
+
+
+
+
+ +
+ + + field + + + field + +
+ +
+ + +
+ +
+ + +
+ +`; diff --git a/src/plugins/advanced_settings/public/management_app/advanced_settings.test.tsx b/src/plugins/advanced_settings/public/management_app/advanced_settings.test.tsx index d1de7a7b4691..052de6b1ea75 100644 --- a/src/plugins/advanced_settings/public/management_app/advanced_settings.test.tsx +++ b/src/plugins/advanced_settings/public/management_app/advanced_settings.test.tsx @@ -40,7 +40,11 @@ import { } from '../../../../core/public'; import { FieldSetting } from './types'; import { AdvancedSettingsComponent } from './advanced_settings'; -import { notificationServiceMock, docLinksServiceMock } from '../../../../core/public/mocks'; +import { + notificationServiceMock, + docLinksServiceMock, + applicationServiceMock, +} from '../../../../core/public/mocks'; import { ComponentRegistry } from '../component_registry'; jest.mock('./components/field', () => ({ @@ -288,4 +292,21 @@ describe('AdvancedSettings', () => { .prop('enableSaving') ).toBe(false); }); + + it('should render normally when use updated UX', async () => { + const component = mountWithI18nProvider( + null, TopNavMenu: () => null }} + application={applicationServiceMock.createStartContract()} + /> + ); + expect(component).toMatchSnapshot(); + }); }); diff --git a/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx b/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx index 680b0e9a36fc..f5034ce08d2b 100644 --- a/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx +++ b/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx @@ -37,12 +37,18 @@ import { CallOuts } from './components/call_outs'; import { Search } from './components/search'; import { Form } from './components/form'; import { AdvancedSettingsVoiceAnnouncement } from './components/advanced_settings_voice_announcement'; -import { IUiSettingsClient, DocLinksStart, ToastsStart } from '../../../../core/public/'; +import { + IUiSettingsClient, + DocLinksStart, + ToastsStart, + ApplicationStart, +} from '../../../../core/public/'; import { ComponentRegistry } from '../'; import { getAriaName, toEditableConfig, DEFAULT_CATEGORY } from './lib'; import { FieldSetting, SettingsChanges } from './types'; +import { NavigationPublicPluginStart } from '../../../../plugins/navigation/public'; interface AdvancedSettingsProps { enableSaving: boolean; @@ -50,6 +56,9 @@ interface AdvancedSettingsProps { dockLinks: DocLinksStart['links']; toasts: ToastsStart; componentRegistry: ComponentRegistry['start']; + useUpdatedUX: boolean; + navigationUI: NavigationPublicPluginStart['ui']; + application: ApplicationStart; } interface AdvancedSettingsComponentProps extends AdvancedSettingsProps { @@ -226,21 +235,50 @@ export class AdvancedSettingsComponent extends Component< ); const PageFooter = componentRegistry.get(componentRegistry.componentType.PAGE_FOOTER_COMPONENT); - return ( -
- - - - - + const renderHeader = () => { + if (!this.props.useUpdatedUX) { + return ( + <> + + + + + + + + + + + + + + ); + } else { + const { HeaderControl } = this.props.navigationUI; + return ( + <> + , + }, + ]} + /> - - - - - - + + + ); + } + }; + return ( +
+ {renderHeader()}
{ dockLinks={props.dockLinks} toasts={props.toasts} componentRegistry={props.componentRegistry} + useUpdatedUX={props.useUpdatedUX} + navigationUI={props.navigationUI} + application={props.application} /> ); }; diff --git a/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx b/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx index fff7a9f1b357..383fc1eb3ccd 100644 --- a/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx +++ b/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx @@ -40,14 +40,10 @@ import { EuiPageContent } from '@elastic/eui'; import { AdvancedSettings } from './advanced_settings'; import { ManagementAppMountParams } from '../../../management/public'; import { ComponentRegistry } from '../types'; +import { NavigationPublicPluginStart } from '../../../../plugins/navigation/public'; import './index.scss'; -const title = i18n.translate('advancedSettings.advancedSettingsLabel', { - defaultMessage: 'Advanced settings', -}); -const crumb = [{ text: title }]; - const readOnlyBadge = { text: i18n.translate('advancedSettings.badge.readOnly.text', { defaultMessage: 'Read only', @@ -59,12 +55,16 @@ const readOnlyBadge = { }; export async function mountManagementSection( - getStartServices: StartServicesAccessor, + getStartServices: StartServicesAccessor<{ + navigation: NavigationPublicPluginStart; + }>, params: ManagementAppMountParams & { wrapInPage?: boolean }, componentRegistry: ComponentRegistry['start'] ) { - params.setBreadcrumbs(crumb); - const [{ uiSettings, notifications, docLinks, application, chrome }] = await getStartServices(); + const [ + { uiSettings, notifications, docLinks, application, chrome }, + { navigation }, + ] = await getStartServices(); const canSave = application.capabilities.advancedSettings.save as boolean; @@ -72,6 +72,18 @@ export async function mountManagementSection( chrome.setBadge(readOnlyBadge); } + const title = i18n.translate('advancedSettings.advancedSettingsLabel', { + defaultMessage: 'Advanced settings', + }); + const newUXTitle = i18n.translate('advancedSettings.newHeader.pageTitle', { + defaultMessage: 'Application settings', + }); + + const useUpdatedUX = uiSettings.get('home:useNewHomePage'); + // If new navigation is off, this will be rendered as breadcrumb. If is on, this will be rendered as title. + const crumb = [{ text: useUpdatedUX ? newUXTitle : title }]; + params.setBreadcrumbs(crumb); + const content = ( @@ -82,6 +94,9 @@ export async function mountManagementSection( dockLinks={docLinks.links} uiSettings={uiSettings} componentRegistry={componentRegistry} + useUpdatedUX={useUpdatedUX} + navigationUI={navigation.ui} + application={application} /> diff --git a/src/plugins/advanced_settings/public/plugin.ts b/src/plugins/advanced_settings/public/plugin.ts index 814a5cde6aba..8c840150529e 100644 --- a/src/plugins/advanced_settings/public/plugin.ts +++ b/src/plugins/advanced_settings/public/plugin.ts @@ -32,7 +32,12 @@ import { i18n } from '@osd/i18n'; import { AppMountParameters, CoreSetup, CoreStart, Plugin } from 'opensearch-dashboards/public'; import { FeatureCatalogueCategory } from '../../home/public'; import { ComponentRegistry } from './component_registry'; -import { AdvancedSettingsSetup, AdvancedSettingsStart, AdvancedSettingsPluginSetup } from './types'; +import { + AdvancedSettingsSetup, + AdvancedSettingsStart, + AdvancedSettingsPluginSetup, + AdvancedSettingsPluginStart, +} from './types'; import { setupTopNavThemeButton } from './register_nav_control'; import { DEFAULT_NAV_GROUPS, AppNavLinkStatus, WorkspaceAvailability } from '../../../core/public'; import { getScopedBreadcrumbs } from '../../opensearch_dashboards_react/public'; @@ -48,8 +53,17 @@ const titleInGroup = i18n.translate('advancedSettings.applicationSettingsLabel', }); export class AdvancedSettingsPlugin - implements Plugin { - public setup(core: CoreSetup, { management, home }: AdvancedSettingsPluginSetup) { + implements + Plugin< + AdvancedSettingsSetup, + AdvancedSettingsStart, + AdvancedSettingsPluginSetup, + AdvancedSettingsPluginStart + > { + public setup( + core: CoreSetup, + { management, home }: AdvancedSettingsPluginSetup + ) { const opensearchDashboardsSection = management.sections.section.opensearchDashboards; opensearchDashboardsSection.registerApp({ diff --git a/src/plugins/advanced_settings/public/types.ts b/src/plugins/advanced_settings/public/types.ts index 24a297ad4d83..68d92a2b856f 100644 --- a/src/plugins/advanced_settings/public/types.ts +++ b/src/plugins/advanced_settings/public/types.ts @@ -32,6 +32,7 @@ import { ComponentRegistry } from './component_registry'; import { HomePublicPluginSetup } from '../../home/public'; import { ManagementSetup } from '../../management/public'; +import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; export interface AdvancedSettingsSetup { component: ComponentRegistry['setup']; @@ -45,4 +46,8 @@ export interface AdvancedSettingsPluginSetup { home?: HomePublicPluginSetup; } +export interface AdvancedSettingsPluginStart { + navigation: NavigationPublicPluginStart; +} + export { ComponentRegistry }; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap index c27e4d7c1487..a6e42f9aee64 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap @@ -224,6 +224,18 @@ exports[`CreateIndexPatternWizard renders when there are no indices but there ar `; +exports[`CreateIndexPatternWizard should render normally when use update UX 1`] = ` + + + + +`; + exports[`CreateIndexPatternWizard shows system indices even if there are no other indices if the include system indices is toggled 1`] = ` diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/__snapshots__/description.test.tsx.snap b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/__snapshots__/description.test.tsx.snap new file mode 100644 index 000000000000..2fd0292b459a --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/__snapshots__/description.test.tsx.snap @@ -0,0 +1,95 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Description render normally 1`] = ` + + +
+

+ + multiple + , + "single": + filebeat-4-3-22 + , + "star": + filebeat-* + , + } + } + > + + An index pattern can match a single source, for example, + + + + + filebeat-4-3-22 + + + + + , or + + multiple + + data sources, + + + + + filebeat-* + + + + + . + + +
+ + + +

+
+
+
+`; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/__snapshots__/header.test.tsx.snap b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/__snapshots__/header.test.tsx.snap index 35c9543af3c7..535766a5fda9 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/__snapshots__/header.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/__snapshots__/header.test.tsx.snap @@ -52,84 +52,96 @@ exports[`Header should render a different name, prompt, and beta tag if provided className="euiSpacer euiSpacer--s" /> - -
-

- - multiple - , - "single": - filebeat-4-3-22 - , - "star": - filebeat-* - , + + +

+

+ + multiple + , + "single": + filebeat-4-3-22 + , + "star": + filebeat-* + , + } } - } - > - - An index pattern can match a single source, for example, - - - - - filebeat-4-3-22 - - - - - , or - - multiple - - data sources, - - + + An index pattern can match a single source, for example, + + + + + filebeat-4-3-22 + + + + + , or + + multiple + + data sources, + + + + + filebeat-* + + + + + . + + +
+ + - -

-
- + + + +

+
+
+ @@ -180,84 +192,96 @@ exports[`Header should render normally 1`] = ` className="euiSpacer euiSpacer--s" /> - -
-

- - multiple - , - "single": - filebeat-4-3-22 - , - "star": - filebeat-* - , + + +

+

+ + multiple + , + "single": + filebeat-4-3-22 + , + "star": + filebeat-* + , + } } - } - > - - An index pattern can match a single source, for example, - - - - - filebeat-4-3-22 - - - - - , or - - multiple - - data sources, - - + + An index pattern can match a single source, for example, + + + + + filebeat-4-3-22 + + + + + , or + + multiple + + data sources, + + + + + filebeat-* + + + + + . + + +
+ + - -

-
- + + + +

+
+
+
@@ -298,84 +322,96 @@ exports[`Header should render without including system indices 1`] = ` className="euiSpacer euiSpacer--s" />
- -
-

- - multiple - , - "single": - filebeat-4-3-22 - , - "star": - filebeat-* - , + + +

+

+ + multiple + , + "single": + filebeat-4-3-22 + , + "star": + filebeat-* + , + } } - } - > - - An index pattern can match a single source, for example, - - - - - filebeat-4-3-22 - - - - - , or - - multiple - - data sources, - - + + An index pattern can match a single source, for example, + + + + + filebeat-4-3-22 + + + + + , or + + multiple + + data sources, + + + + + filebeat-* + + + + + . + + +
+ + - -

-
- + + + +

+
+
+
diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.test.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.test.tsx new file mode 100644 index 000000000000..f9b4efc7acb0 --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.test.tsx @@ -0,0 +1,18 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Description } from './description'; +import { mount } from 'enzyme'; +import React from 'react'; +import { mockManagementPlugin } from '../../../../mocks'; + +const mockContext = mockManagementPlugin.createIndexPatternManagmentContext(); + +describe('Description', () => { + it('render normally', () => { + const component = mount(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.tsx new file mode 100644 index 000000000000..cd6036f212ad --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.tsx @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { FormattedMessage } from '@osd/i18n/react'; +import { DocLinksStart } from 'opensearch-dashboards/public'; + +import { EuiText, EuiCode, EuiLink } from '@elastic/eui'; + +interface Props { + docLinks: DocLinksStart; +} + +export const Description = ({ docLinks }: Props) => ( + +

+ multiple, + single: filebeat-4-3-22, + star: filebeat-*, + }} + /> +
+ + + +

+
+); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/header.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/header.tsx index 5a0ab5018d2e..8e0ec8c4a8b8 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/header.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/header.tsx @@ -30,13 +30,13 @@ import React from 'react'; -import { EuiBetaBadge, EuiSpacer, EuiText, EuiCode, EuiLink } from '@elastic/eui'; +import { EuiBetaBadge, EuiSpacer, EuiText } from '@elastic/eui'; import { i18n } from '@osd/i18n'; -import { FormattedMessage } from '@osd/i18n/react'; import { DocLinksStart } from 'opensearch-dashboards/public'; import { useOpenSearchDashboards } from '../../../../../../opensearch_dashboards_react/public'; import { IndexPatternManagmentContext } from '../../../../types'; +import { Description } from './description'; export const Header = ({ prompt, @@ -79,30 +79,7 @@ export const Header = ({ - -

- multiple, - single: filebeat-4-3-22, - star: filebeat-*, - }} - /> -
- - - -

-
+ {prompt ? ( <> diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/index.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/index.ts index 47ff6e19434b..1846268f1fa7 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/index.ts +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/index.ts @@ -29,3 +29,4 @@ */ export { Header } from './header'; +export { Description } from './description'; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx index 7795c20dafd5..a1f958e03075 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx @@ -182,4 +182,15 @@ describe('CreateIndexPatternWizard', () => { expect(clear).toBeCalledWith('1'); expect(routeComponentPropsMock.history.push).toBeCalledWith(`/patterns/1`); }); + + test('should render normally when use update UX', () => { + mockContext.uiSettings.get = () => true; + const component = createComponentWithContext( + CreateIndexPatternWizard, + { ...routeComponentPropsMock }, + mockContext + ); + + expect(component).toMatchSnapshot(); + }); }); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx index 337efa752aee..6f02c98aa4f8 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx @@ -42,7 +42,7 @@ import { withRouter, RouteComponentProps } from 'react-router-dom'; import { DocLinksStart } from 'src/core/public'; import { StepIndexPattern } from './components/step_index_pattern'; import { StepTimeField } from './components/step_time_field'; -import { Header } from './components/header'; +import { Header, Description } from './components/header'; import { LoadingState } from './components/loading_state'; import { context as contextType } from '../../../../opensearch_dashboards_react/public'; @@ -273,7 +273,14 @@ export class CreateIndexPatternWizard extends Component< } renderContent() { - const { allIndices, isInitiallyLoadingIndices, step, indexPattern, dataSourceRef } = this.state; + const { + allIndices, + isInitiallyLoadingIndices, + step, + indexPattern, + dataSourceRef, + docLinks, + } = this.state; const stepInfo = { totalStepNumber: this.totalSteps, @@ -281,6 +288,9 @@ export class CreateIndexPatternWizard extends Component< }; const hideLocalCluster = this.context.services.hideLocalCluster; + const useUpdatedUX = this.context.services.uiSettings.get('home:useNewHomePage'); + const { HeaderControl } = this.context.services.navigationUI; + const application = this.context.services.application; if (isInitiallyLoadingIndices) { return ; @@ -289,15 +299,30 @@ export class CreateIndexPatternWizard extends Component< const header = this.renderHeader(); if (step === DATA_SOURCE_STEP) { - return ( + const component = ( + + ); + return useUpdatedUX ? ( + <> + {component} + , + }, + ]} + setMountPoint={application.setAppDescriptionControls} + /> + + ) : ( {header} - + {component} ); } @@ -305,43 +330,74 @@ export class CreateIndexPatternWizard extends Component< if (step === INDEX_PATTERN_STEP) { const { location } = this.props; const initialQuery = new URLSearchParams(location.search).get('id') || undefined; - - return ( + const component = ( + + ); + return useUpdatedUX ? ( + <> + {/* Except StepDataSource, other components need to use PageContent to wrap when using new UX */} + {component} + , + }, + ]} + setMountPoint={application.setAppDescriptionControls} + /> + + ) : ( {header} - + {component} ); } if (step === TIME_FIELD_STEP) { - return ( + const component = ( + + ); + return useUpdatedUX ? ( + <> + {/* Except StepDataSource, other components need to use PageContent to wrap when using new UX */} + {component} + , + }, + ]} + setMountPoint={application.setAppDescriptionControls} + /> + + ) : ( {header} - + {component} ); } diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx index 76689ab7c553..a39dcd6cc5a2 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx @@ -101,6 +101,8 @@ export const EditIndexPattern = withRouter( chrome, data, docLinks, + navigationUI: { HeaderControl }, + application, } = useOpenSearchDashboards().services; const [fields, setFields] = useState(indexPattern.getNonScriptedFields()); const [conflictedFields, setConflictedFields] = useState( @@ -196,7 +198,99 @@ export const EditIndexPattern = withRouter( const showTagsSection = Boolean(indexPattern.timeFieldName || (tags && tags.length > 0)); - return ( + const useUpdatedUX = uiSettings.get('home:useNewHomePage'); + + const renderDescription = () => { + const component = ( + +

+ {indexPattern.title} }} + />{' '} + + {mappingAPILink} + +

+
+ ); + + return useUpdatedUX ? ( + + ) : ( + component + ); + }; + + const renderBadges = () => { + if (useUpdatedUX) { + const components = [ + ...(Boolean(indexPattern.timeFieldName) + ? [{timeFilterHeader}] + : []), + ...tags.map((tag: any) => {tag.name}), + ]; + const controls = components.map((component) => ({ + renderComponent: component, + })); + + return ( + + ); + } else { + return ( + + {Boolean(indexPattern.timeFieldName) && ( + + {timeFilterHeader} + + )} + {tags.map((tag: any) => ( + + {tag.name} + + ))} + + ); + } + }; + + return useUpdatedUX ? ( +
+ + {showTagsSection && renderBadges()} + {renderDescription()} + {conflictedFields.length > 0 && ( + <> + + +

{mappingConflictLabel}

+
+ + )} + +
+ ) : (
- {showTagsSection && ( - - {Boolean(indexPattern.timeFieldName) && ( - - {timeFilterHeader} - - )} - {tags.map((tag: any) => ( - - {tag.name} - - ))} - - )} + {showTagsSection && renderBadges()} - -

- {indexPattern.title} }} - />{' '} - - {mappingAPILink} - -

-
+ {renderDescription()} {conflictedFields.length > 0 && ( <> diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx index 386e0d840e1d..156a22f720f5 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx @@ -30,8 +30,18 @@ import React from 'react'; import { i18n } from '@osd/i18n'; -import { EuiFlexGroup, EuiToolTip, EuiFlexItem, EuiSmallButtonIcon, EuiText } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiToolTip, + EuiFlexItem, + EuiSmallButtonIcon, + EuiText, + EuiButtonIcon, + EuiButton, +} from '@elastic/eui'; import { IIndexPattern } from 'src/plugins/data/public'; +import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; +import { IndexPatternManagmentContext } from '../../../types'; interface IndexHeaderProps { indexPattern: IIndexPattern; @@ -78,7 +88,85 @@ export function IndexHeader({ refreshFields, deleteIndexPatternClick, }: IndexHeaderProps) { - return ( + const { + uiSettings, + navigationUI: { HeaderControl }, + application, + } = useOpenSearchDashboards().services; + + const useUpdatedUX = uiSettings.get('home:useNewHomePage'); + + return useUpdatedUX ? ( + + + + ), + }, + ] + : []), + ...(defaultIndex !== indexPattern.id && setDefault + ? [ + { + renderComponent: ( + + {i18n.translate( + 'indexPatternManagement.editIndexPattern.setDefaultButton.text', + { + defaultMessage: 'Set as default index', + } + )} + + ), + }, + ] + : []), + ...(refreshFields + ? [ + { + renderComponent: ( + + {i18n.translate( + 'indexPatternManagement.editIndexPattern.refreshFieldsButton.text', + { + defaultMessage: 'Refresh field list', + } + )} + + ), + }, + ] + : []), + ]} + setMountPoint={application.setAppRightControls} + /> + ) : ( diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx index 613958bd2a3c..fdceab0f5e59 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx @@ -39,6 +39,7 @@ import { EuiCompressedFieldSearch, EuiCompressedSelect, EuiSelectOption, + EuiPageContent, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { fieldWildcardMatcher } from '../../../../../opensearch_dashboards_utils/public'; @@ -125,6 +126,8 @@ export function Tabs({ indexPattern, saveIndexPattern, fields, history, location [uiSettings] ); + const useUpdatedUX = uiSettings.get('home:useNewHomePage'); + const getFilterSection = useCallback( (type: string) => { return ( @@ -174,63 +177,73 @@ export function Tabs({ indexPattern, saveIndexPattern, fields, history, location const getContent = useCallback( (type: string) => { + const Wrapper = useUpdatedUX ? EuiPageContent : Fragment; switch (type) { case TAB_INDEXED_FIELDS: return ( - - - {getFilterSection(type)} - - { - history.push(getPath(field, indexPattern)); - }, - getFieldInfo: indexPatternManagementStart.list.getFieldInfo, - }} - /> - + <> + {useUpdatedUX && } + + + {getFilterSection(type)} + + { + history.push(getPath(field, indexPattern)); + }, + getFieldInfo: indexPatternManagementStart.list.getFieldInfo, + }} + /> + + ); case TAB_SCRIPTED_FIELDS: return ( - - - {getFilterSection(type)} - - { - history.push(getPath(field, indexPattern)); - }, - }} - onRemoveField={refreshFilters} - painlessDocLink={docLinks.links.noDocumentation.scriptedFields.painless} - /> - + <> + {useUpdatedUX && } + + + {getFilterSection(type)} + + { + history.push(getPath(field, indexPattern)); + }, + }} + onRemoveField={refreshFilters} + painlessDocLink={docLinks.links.noDocumentation.scriptedFields.painless} + /> + + ); case TAB_SOURCE_FILTERS: return ( - - - {getFilterSection(type)} - - - + <> + {useUpdatedUX && } + + + {getFilterSection(type)} + + + + ); } }, @@ -247,6 +260,7 @@ export function Tabs({ indexPattern, saveIndexPattern, fields, history, location refreshFilters, scriptedFieldLanguageFilter, saveIndexPattern, + useUpdatedUX, ] ); diff --git a/src/plugins/index_pattern_management/public/mocks.ts b/src/plugins/index_pattern_management/public/mocks.ts index dacf876c2f6c..39731abf733b 100644 --- a/src/plugins/index_pattern_management/public/mocks.ts +++ b/src/plugins/index_pattern_management/public/mocks.ts @@ -126,6 +126,9 @@ const createIndexPatternManagmentContext = () => { data, indexPatternManagementStart: createStartContract(), setBreadcrumbs: () => {}, + navigationUI: { + HeaderControl: () => null, + }, }; }; diff --git a/src/plugins/management/public/components/management_app/management_app.tsx b/src/plugins/management/public/components/management_app/management_app.tsx index c30243563b01..1241bb571326 100644 --- a/src/plugins/management/public/components/management_app/management_app.tsx +++ b/src/plugins/management/public/components/management_app/management_app.tsx @@ -38,6 +38,7 @@ import { ManagementRouter } from './management_router'; import { ManagementSidebarNav } from '../management_sidebar_nav'; import { reactRouterNavigate } from '../../../../opensearch_dashboards_react/public'; import { SectionsServiceStart } from '../../types'; +import { CoreStart } from '../../../../../core/public'; import './management_app.scss'; @@ -52,6 +53,7 @@ export interface ManagementAppDependencies { opensearchDashboardsVersion: string; setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void; hideInAppNavigation?: boolean; + uiSettings: CoreStart['uiSettings']; } export const ManagementApp = ({ dependencies, history }: ManagementAppProps) => { diff --git a/src/plugins/management/public/components/management_app/management_router.tsx b/src/plugins/management/public/components/management_app/management_router.tsx index 06c39570c7da..0e7ca593f69f 100644 --- a/src/plugins/management/public/components/management_app/management_router.tsx +++ b/src/plugins/management/public/components/management_app/management_router.tsx @@ -46,38 +46,46 @@ interface ManagementRouterProps { } export const ManagementRouter = memo( - ({ dependencies, history, setBreadcrumbs, onAppMounted, sections }: ManagementRouterProps) => ( - - - - {sections.map((section) => - section - .getAppsEnabled() - .map((app) => ( - ( - - )} - /> - )) - )} - ( - + ({ dependencies, history, setBreadcrumbs, onAppMounted, sections }: ManagementRouterProps) => { + const useUpdatedUX = dependencies.uiSettings.get('home:useNewHomePage'); + return ( + + + + {sections.map((section) => + section + .getAppsEnabled() + .map((app) => ( + ( + + )} + /> + )) )} - /> - - - - ) + ( + + )} + /> + + + + ); + } ); diff --git a/src/plugins/management/public/plugin.ts b/src/plugins/management/public/plugin.ts index 7b219bffad9e..00fd767b27fb 100644 --- a/src/plugins/management/public/plugin.ts +++ b/src/plugins/management/public/plugin.ts @@ -110,6 +110,7 @@ export class ManagementPlugin opensearchDashboardsVersion, setBreadcrumbs: coreStart.chrome.setBreadcrumbs, hideInAppNavigation, + uiSettings: coreStart.uiSettings, }); }, }); diff --git a/src/plugins/saved_objects_management/opensearch_dashboards.json b/src/plugins/saved_objects_management/opensearch_dashboards.json index 2802eb04b3dc..9a985345b030 100644 --- a/src/plugins/saved_objects_management/opensearch_dashboards.json +++ b/src/plugins/saved_objects_management/opensearch_dashboards.json @@ -3,7 +3,7 @@ "version": "opensearchDashboards", "server": true, "ui": true, - "requiredPlugins": ["management", "data", "uiActions"], + "requiredPlugins": ["management", "data", "uiActions","navigation"], "optionalPlugins": [ "dashboard", "visualizations", diff --git a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx index 0c98f365b39d..e26956900627 100644 --- a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx +++ b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx @@ -64,7 +64,7 @@ export const mountManagementSection = async ({ dataSourceEnabled, dataSourceManagement, }: MountParams) => { - const [coreStart, { data, uiActions }, pluginStart] = await core.getStartServices(); + const [coreStart, { data, uiActions, navigation }, pluginStart] = await core.getStartServices(); const { element, history, setBreadcrumbs } = mountParams; if (allowedObjectTypes === undefined) { allowedObjectTypes = await getAllowedTypes(coreStart.http); @@ -89,6 +89,8 @@ export const mountManagementSection = async ({ return children! as React.ReactElement; }; + const useUpdatedUX = coreStart.uiSettings.get('home:useNewHomePage'); + const content = ( @@ -119,6 +121,8 @@ export const mountManagementSection = async ({ setBreadcrumbs={setBreadcrumbs} dataSourceEnabled={dataSourceEnabled} dataSourceManagement={dataSourceManagement} + navigation={navigation} + useUpdatedUX={useUpdatedUX} /> diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap index 765a84bb0803..769444715a90 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap @@ -992,6 +992,51 @@ exports[`SavedObjectsTable should render normally 1`] = ` horizontalPosition="center" >
`; + +exports[`Header should render normally when useUpdatedUX is true 1`] = ` + + + + + , + }, + Object { + "renderComponent": + + , + }, + Object { + "renderComponent": + + , + }, + ] + } + setMountPoint={[MockFunction]} + /> + + + + + +`; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap index 6c14a3084527..c0537471afa3 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap @@ -26,6 +26,7 @@ exports[`Table prevents saved objects from being deleted 1`] = ` onChange={[Function]} toolsRight={ Array [ + , , , , + , + + + , + + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="s" + > + + } + labelType="label" + > + + } + name="includeReferencesDeep" + onChange={[Function]} + /> + + + + + + + , + ] + } + /> + +
+ +
+ +`; + +exports[`Table should render normally when use updated UX 1`] = ` + + + +
, , {}, + onImport: () => {}, + onRefresh: () => {}, + onDuplicate: () => {}, + objectCount: 4, + filteredCount: 2, + useUpdatedUX: false, + navigationUI: { HeaderControl: () => null, TopNavMenu: () => null }, + applications: applicationServiceMock.createStartContract(), +}; describe('Header', () => { it('should render normally', () => { const props = { - onExportAll: () => {}, - onImport: () => {}, - onRefresh: () => {}, - onDuplicate: () => {}, - objectCount: 4, - filteredCount: 2, + ...defaultProps, showDuplicateAll: false, }; @@ -51,12 +59,7 @@ describe('Header', () => { it('should render normally when showDuplicateAll is undefined', () => { const props = { - onExportAll: () => {}, - onImport: () => {}, - onRefresh: () => {}, - onDuplicate: () => {}, - objectCount: 4, - filteredCount: 2, + ...defaultProps, showDuplicateAll: undefined, }; @@ -64,17 +67,24 @@ describe('Header', () => { expect(component).toMatchSnapshot(); }); + + it('should render normally when useUpdatedUX is true', () => { + const props = { + ...defaultProps, + showDuplicateAll: true, + useUpdatedUX: true, + }; + + const component = shallow(
); + + expect(component).toMatchSnapshot(); + }); }); describe('Header - workspace enabled', () => { it('should render `Duplicate All` button when workspace enabled', () => { const props = { - onExportAll: () => {}, - onImport: () => {}, - onRefresh: () => {}, - onDuplicate: () => {}, - objectCount: 4, - filteredCount: 2, + ...defaultProps, showDuplicateAll: true, }; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx index f83cdfaf69f2..80f37d53ceec 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx @@ -36,8 +36,12 @@ import { EuiText, EuiTextColor, EuiButtonEmpty, + EuiButton, } from '@elastic/eui'; import { FormattedMessage } from '@osd/i18n/react'; +import { ApplicationStart } from 'src/core/public'; +import { i18n } from '@osd/i18n'; +import { NavigationPublicPluginStart } from '../../../../../navigation/public'; export const Header = ({ onExportAll, @@ -46,6 +50,9 @@ export const Header = ({ onRefresh, objectCount, showDuplicateAll = false, + useUpdatedUX, + navigationUI: { HeaderControl }, + applications, }: { onExportAll: () => void; onImport: () => void; @@ -53,40 +60,72 @@ export const Header = ({ onRefresh: () => void; objectCount: number; showDuplicateAll: boolean; -}) => ( - - - - -

- -

-
-
+ useUpdatedUX: boolean; + navigationUI: NavigationPublicPluginStart['ui']; + applications: ApplicationStart; +}) => { + const title = useUpdatedUX ? null : ( + + +

+ +

+
+
+ ); + const description = useUpdatedUX ? ( + + ) : ( + +

+ + + +

+
+ ); - - - {showDuplicateAll && ( - - - - - - )} - - + + + ), + }, + ] + : []), + { + renderComponent: ( + - - - - + ), + }, + { + renderComponent: ( + - - + + ), + }, + ]} + setMountPoint={applications.setAppRightControls} + /> + ) : ( + + + {showDuplicateAll && ( - + - - - - - -

- - - -

-
- -
-); + )} + + + + + + + + + + + + + + + + + + ); + + return ( + + + {title} + {rightControls} + + + {description} + + + ); +}; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx index e9b5595dd45d..ddf50e68c25a 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx @@ -110,6 +110,7 @@ const defaultProps: TableProps = { onDuplicate: () => {}, onDuplicateSingle: () => {}, showDuplicate: false, + useUpdatedUX: false, }; describe('Table', () => { @@ -119,6 +120,16 @@ describe('Table', () => { expect(component).toMatchSnapshot(); }); + it('should render normally when use updated UX', () => { + const props = { + ...defaultProps, + useUpdatedUX: true, + }; + const component = shallowWithI18nProvider(); + + expect(component).toMatchSnapshot(); + }); + it('should render gotoApp link correctly for workspace', () => { const item = { id: 'dashboard-1', diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx index 1341461a800e..fdfd2cea2c28 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx @@ -47,6 +47,7 @@ import { EuiTableFieldDataColumnType, EuiTableActionsColumnType, EuiSearchBarProps, + EuiButtonIcon, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { FormattedMessage } from '@osd/i18n/react'; @@ -90,6 +91,8 @@ export interface TableProps { availableWorkspaces?: WorkspaceAttribute[]; currentWorkspaceId?: string; showDuplicate: boolean; + useUpdatedUX: boolean; + onRefresh: () => void; } interface TableState { @@ -189,6 +192,8 @@ export class Table extends PureComponent { availableWorkspaces, currentWorkspaceId, showDuplicate, + useUpdatedUX, + onRefresh, } = this.props; const visibleWsIds = availableWorkspaces?.map((ws) => ws.id) || []; @@ -417,6 +422,17 @@ export class Table extends PureComponent { filters={filters} onChange={this.onChange} toolsRight={[ + <> + {useUpdatedUX && ( + + )} + , <>{showDuplicate && duplicateButton}, @@ -1191,6 +1204,8 @@ export class SavedObjectsTable extends Component diff --git a/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx index 425baca096d2..f526f7f6c751 100644 --- a/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx +++ b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx @@ -41,6 +41,7 @@ import { SavedObjectsManagementNamespaceServiceStart, } from '../services'; import { SavedObjectsTable } from './objects_table'; +import { NavigationPublicPluginStart } from '../../../navigation/public'; const SavedObjectsTablePage = ({ coreStart, @@ -53,6 +54,8 @@ const SavedObjectsTablePage = ({ setBreadcrumbs, dataSourceEnabled, dataSourceManagement, + navigation, + useUpdatedUX, }: { coreStart: CoreStart; dataStart: DataPublicPluginStart; @@ -64,6 +67,8 @@ const SavedObjectsTablePage = ({ setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; dataSourceEnabled: boolean; dataSourceManagement?: DataSourceManagementPluginSetup; + navigation: NavigationPublicPluginStart; + useUpdatedUX: boolean; }) => { const capabilities = coreStart.application.capabilities; const itemsPerPage = coreStart.uiSettings.get('savedObjects:perPage', 50); @@ -71,14 +76,20 @@ const SavedObjectsTablePage = ({ useEffect(() => { setBreadcrumbs([ - { - text: i18n.translate('savedObjectsManagement.breadcrumb.index', { - defaultMessage: 'Saved objects', - }), - href: '/', - }, + useUpdatedUX + ? { + text: i18n.translate('savedObjectsManagement.updatedUX.title', { + defaultMessage: 'Assets', + }), + } + : { + text: i18n.translate('savedObjectsManagement.breadcrumb.index', { + defaultMessage: 'Saved objects', + }), + href: '/', + }, ]); - }, [setBreadcrumbs]); + }, [setBreadcrumbs, useUpdatedUX]); return ( ); }; diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts index 65c91d6ff14c..2f69c1587c65 100644 --- a/src/plugins/saved_objects_management/public/plugin.ts +++ b/src/plugins/saved_objects_management/public/plugin.ts @@ -67,6 +67,7 @@ import { DEFAULT_NAV_GROUPS } from '../../../core/public'; import { RecentWork } from './management_section/recent_work'; import { HOME_CONTENT_AREAS } from '../../../plugins/home/public'; import { getScopedBreadcrumbs } from '../../opensearch_dashboards_react/public'; +import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; /** * The id is used in src/plugins/workspace/public/plugin.ts and please change that accordingly if you change the id here. @@ -104,6 +105,7 @@ export interface StartDependencies { visBuilder?: VisBuilderStart; uiActions: UiActionsStart; contentManagement?: ContentManagementPluginStart; + navigation: NavigationPublicPluginStart; } export class SavedObjectsManagementPlugin