mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 11:05:39 -04:00
- Closes https://github.com/elastic/kibana/issues/210500 - Closes https://github.com/elastic/kibana/issues/210502 ## Summary This PR introduces a new package `@kbn/unified-tabs` which includes an initial implementation for tabs UI/UX which we are planning to add to Discover. - [x] New package - [x] Storybook support - [x] Initial styles and interactions - [x] New example plugin for testing together with UnifiedSearch bar - [x] Minimal tests ### In the new Storybook Start Storybook with `NODE_OPTIONS="--openssl-legacy-provider" node scripts/storybook unified_tabs` and navigate to `http://localhost:9001`. <img width="1024" alt="Screenshot 2025-02-12 at 13 35 46" src="https://github.com/user-attachments/assets/0723b0c4-c3f7-44f8-af8d-f68d7a7b6ea8" /> ### In the new Unified Tabs example plugin Start Kibana with `yarn start --run-examples`. Then navigate to the Unified Tabs example plugin `http://localhost:5601/app/unifiedTabsExamples`. <img width="1221" alt="Screenshot 2025-02-12 at 16 11 55" src="https://github.com/user-attachments/assets/2edff817-0aae-424c-978c-c4c67450c9eb" /> <img width="1219" alt="Screenshot 2025-02-12 at 16 13 57" src="https://github.com/user-attachments/assets/2e6e6b0b-88e9-4689-a175-9612e8507535" />  ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Davis McPhee <davismcphee@hotmail.com>
132 lines
4.4 KiB
TypeScript
132 lines
4.4 KiB
TypeScript
/*
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
* or more contributor license agreements. Licensed under the "Elastic License
|
|
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
|
* Public License v 1"; you may not use this file except in compliance with, at
|
|
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
|
*/
|
|
|
|
import React, { useState } from 'react';
|
|
import ReactDOM from 'react-dom';
|
|
|
|
import {
|
|
EuiText,
|
|
EuiPageTemplate,
|
|
EuiCard,
|
|
EuiPageHeader,
|
|
EuiFlexGroup,
|
|
EuiFlexItem,
|
|
EuiFieldSearch,
|
|
EuiListGroup,
|
|
EuiHighlight,
|
|
EuiLink,
|
|
EuiButtonIcon,
|
|
} from '@elastic/eui';
|
|
import {
|
|
AnalyticsServiceStart,
|
|
AppMountParameters,
|
|
I18nStart,
|
|
ThemeServiceStart,
|
|
UserProfileService,
|
|
} from '@kbn/core/public';
|
|
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
|
|
import { ExampleDefinition } from './types';
|
|
|
|
interface StartServices {
|
|
analytics: Pick<AnalyticsServiceStart, 'reportEvent'>;
|
|
i18n: I18nStart;
|
|
theme: Pick<ThemeServiceStart, 'theme$'>;
|
|
userProfile: UserProfileService;
|
|
}
|
|
|
|
interface Props {
|
|
startServices: StartServices;
|
|
examples: ExampleDefinition[];
|
|
navigateToApp: (appId: string) => void;
|
|
getUrlForApp: (appId: string) => string;
|
|
}
|
|
|
|
function DeveloperExamples({ startServices, examples, navigateToApp, getUrlForApp }: Props) {
|
|
const [search, setSearch] = useState<string>('');
|
|
|
|
const lcSearch = search.toLowerCase();
|
|
const filteredExamples = !lcSearch
|
|
? examples
|
|
: examples.filter((def) => {
|
|
if (def.description.toLowerCase().indexOf(lcSearch) >= 0) return true;
|
|
if (def.title.toLowerCase().indexOf(lcSearch) >= 0) return true;
|
|
return false;
|
|
});
|
|
|
|
return (
|
|
<KibanaRenderContextProvider {...startServices}>
|
|
<EuiPageTemplate offset={0}>
|
|
<EuiPageTemplate.Header>
|
|
<EuiFlexGroup justifyContent={'spaceBetween'}>
|
|
<EuiFlexItem>
|
|
<EuiPageHeader pageTitle={'Developer examples'} />
|
|
<EuiText>
|
|
The following examples showcase services and APIs that are available to developers.
|
|
</EuiText>
|
|
</EuiFlexItem>
|
|
<EuiFlexItem>
|
|
<EuiFieldSearch
|
|
fullWidth
|
|
placeholder="Search"
|
|
value={search}
|
|
onChange={(e) => setSearch(e.target.value)}
|
|
isClearable={true}
|
|
aria-label="Search developer examples"
|
|
/>
|
|
</EuiFlexItem>
|
|
</EuiFlexGroup>
|
|
</EuiPageTemplate.Header>
|
|
<EuiPageTemplate.Section>
|
|
<EuiFlexGroup wrap>
|
|
{filteredExamples.map((def) => (
|
|
<EuiFlexItem style={{ minWidth: 300, maxWidth: 500 }} key={def.appId}>
|
|
<EuiCard
|
|
description={
|
|
<EuiHighlight search={search} highlightAll={true}>
|
|
{def.description}
|
|
</EuiHighlight>
|
|
}
|
|
title={
|
|
<React.Fragment>
|
|
<EuiLink
|
|
onClick={() => {
|
|
navigateToApp(def.appId);
|
|
}}
|
|
>
|
|
<EuiHighlight search={search} highlightAll={true}>
|
|
{def.title}
|
|
</EuiHighlight>
|
|
</EuiLink>
|
|
<EuiButtonIcon
|
|
iconType="popout"
|
|
onClick={() =>
|
|
window.open(getUrlForApp(def.appId), '_blank', 'noopener, noreferrer')
|
|
}
|
|
>
|
|
Open in new tab
|
|
</EuiButtonIcon>
|
|
</React.Fragment>
|
|
}
|
|
image={def.image}
|
|
footer={def.links ? <EuiListGroup size={'s'} listItems={def.links} /> : undefined}
|
|
/>
|
|
</EuiFlexItem>
|
|
))}
|
|
</EuiFlexGroup>
|
|
</EuiPageTemplate.Section>
|
|
</EuiPageTemplate>
|
|
</KibanaRenderContextProvider>
|
|
);
|
|
}
|
|
|
|
export const renderApp = (props: Props, element: AppMountParameters['element']) => {
|
|
ReactDOM.render(<DeveloperExamples {...props} />, element);
|
|
|
|
return () => ReactDOM.unmountComponentAtNode(element);
|
|
};
|