Skip to content

Commit

Permalink
[ML] Reorganize ML navigation with top and sub level tabs (#45220) (#…
Browse files Browse the repository at this point in the history
…45517)

* Add main nav tabs with sub tabs for new nav

* move transforms to top level main nav

* Make top nav normal font weight

* Update breadcrumbs to take top nav into account

* proper spacing when settings selected

* fix localization error

* Fix functional tests. Update breadcrumbs

* revert analytics breadcrumb update. save for follow up

* ensure main/sub tabs align left

* update dataVisualizer breadcrumbs

* update typescript for tabs
  • Loading branch information
alvarezmelissa87 authored Sep 12, 2019
1 parent a60b6a0 commit af52ef0
Show file tree
Hide file tree
Showing 15 changed files with 298 additions and 106 deletions.
21 changes: 21 additions & 0 deletions x-pack/legacy/plugins/ml/public/breadcrumbs.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,24 @@ export const ML_BREADCRUMB = Object.freeze({
}),
href: '#/'
});

export const SETTINGS = Object.freeze({
text: i18n.translate('xpack.ml.settingsBreadcrumbLabel', {
defaultMessage: 'Settings'
}),
href: '#/settings?'
});

export const ANOMALY_DETECTION_BREADCRUMB = Object.freeze({
text: i18n.translate('xpack.ml.anomalyDetectionBreadcrumbLabel', {
defaultMessage: 'Anomaly Detection'
}),
href: '#/jobs?'
});

export const DATA_VISUALIZER_BREADCRUMB = Object.freeze({
text: i18n.translate('xpack.ml.datavisualizerBreadcrumbLabel', {
defaultMessage: 'Data Visualizer'
}),
href: '#/datavisualizer?'
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
.mlNavigationMenu__tab {
padding-bottom: 0;
padding-left: 0px;
padding-right: 0px;
margin-left: $euiSizeM;
}

.mlNavigationMenu__mainTab {
margin-left: $euiSizeM;
padding-bottom: 0;
font-weight: normal;
}

.mlNavigationMenu__topNav {
padding-top: $euiSizeS;
}

.mlNavHorizontalRule {
margin: $euiSizeM 0 0 0;
}

.mlSubTabs {
margin-top: $euiSizeS;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { FC, useState } from 'react';
import { EuiTabs, EuiTab, EuiLink } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import chrome from 'ui/chrome';
import { TabId } from './navigation_menu';

export interface Tab {
id: TabId;
name: any;
disabled: boolean;
}

interface Props {
disableLinks: boolean;
tabId: TabId;
}

function getTabs(disableLinks: boolean): Tab[] {
return [
// {
// id: 'overview',
// name: i18n.translate('xpack.ml.navMenu.overviewTabLinkText', {
// defaultMessage: 'Overview',
// }),
// disabled: disableLinks,
// },
{
id: 'anomaly_detection',
name: i18n.translate('xpack.ml.navMenu.anomalyDetectionTabLinkText', {
defaultMessage: 'Anomaly Detection',
}),
disabled: disableLinks,
},
{
id: 'data_frames',
name: i18n.translate('xpack.ml.navMenu.dataFrameTabLinkText', {
defaultMessage: 'Transforms',
}),
disabled: false,
},
{
id: 'data_frame_analytics',
name: i18n.translate('xpack.ml.navMenu.dataFrameAnalyticsTabLinkText', {
defaultMessage: 'Data Frame Analytics',
}),
disabled: disableLinks,
},
{
id: 'datavisualizer',
name: i18n.translate('xpack.ml.navMenu.dataVisualizerTabLinkText', {
defaultMessage: 'Data Visualizer',
}),
disabled: false,
},
];
}
interface TabData {
testSubject: string;
pathId?: string;
}

const TAB_DATA: Record<TabId, TabData> = {
// overview: { testSubject: 'mlTabOverview', pathId: 'overview' },
anomaly_detection: { testSubject: 'mlTabAnomalyDetection', pathId: 'jobs' },
data_frames: { testSubject: 'mlTabDataFrames' },
data_frame_analytics: { testSubject: 'mlTabDataFrameAnalytics' },
datavisualizer: { testSubject: 'mlTabDataVisualizer' },
};

export const MainTabs: FC<Props> = ({ tabId, disableLinks }) => {
const [selectedTabId, setSelectedTabId] = useState(tabId);
function onSelectedTabChanged(id: string) {
setSelectedTabId(id);
}

const tabs = getTabs(disableLinks);

return (
<EuiTabs display="condensed">
{tabs.map((tab: Tab) => {
const id = tab.id;
const testSubject = TAB_DATA[id].testSubject;
const defaultPathId = TAB_DATA[id].pathId || id;
return (
<EuiLink
data-test-subj={testSubject}
href={`${chrome.getBasePath()}/app/ml#/${defaultPathId}`}
key={`${id}-key`}
color="text"
>
<EuiTab
className={'mlNavigationMenu__mainTab'}
onClick={() => onSelectedTabChanged(id)}
isSelected={id === selectedTabId}
disabled={tab.disabled}
>
{tab.name}
</EuiTab>
</EuiLink>
);
})}
</EuiTabs>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,54 @@
*/

import React, { Fragment, FC } from 'react';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule } from '@elastic/eui';

// @ts-ignore
import { isFullLicense } from '../../license/check_license';

import { TopNav } from './top_nav';
import { MainTabs } from './main_tabs';
import { Tabs } from './tabs';

const tabSupport = [
'jobs',
'settings',
'data_frames',
'data_frame_analytics',
'datavisualizer',
'filedatavisualizer',
'timeseriesexplorer',
'access-denied',
'explorer',
];
export type TabId = string;
type TabSupport = Record<TabId, string | null>;

const tabSupport: TabSupport = {
// overview: null,
jobs: 'anomaly_detection',
settings: 'anomaly_detection',
data_frames: null,
data_frame_analytics: null,
datavisualizer: null,
filedatavisualizer: null,
timeseriesexplorer: 'anomaly_detection',
'access-denied': null,
explorer: 'anomaly_detection',
};

interface Props {
tabId: string;
tabId: TabId;
}

export const NavigationMenu: FC<Props> = ({ tabId }) => {
const disableLinks = isFullLicense() === false;
const showTabs = tabSupport.includes(tabId);
const showTabs = typeof tabSupport[tabId] !== 'undefined';
const mainTabId = tabSupport[tabId] || tabId;
// show horizontal rule if there are no subtabs
const showHorizontalRule = tabSupport[tabId] === null;

return (
<Fragment>
<EuiFlexGroup justifyContent="flexEnd" gutterSize="xs">
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
{showTabs && <MainTabs tabId={mainTabId} disableLinks={disableLinks} />}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<TopNav />
</EuiFlexItem>
</EuiFlexGroup>
{showTabs && <Tabs tabId={tabId} disableLinks={disableLinks} />}
{showHorizontalRule && <EuiHorizontalRule className="mlNavHorizontalRule" />}
{showTabs && <Tabs tabId={tabId} mainTabId={mainTabId} disableLinks={disableLinks} />}
</Fragment>
);
};
111 changes: 47 additions & 64 deletions x-pack/legacy/plugins/ml/public/components/navigation_menu/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,94 +8,77 @@ import React, { FC, useState } from 'react';
import { EuiTabs, EuiTab, EuiLink } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import chrome from 'ui/chrome';

interface Tab {
id: string;
name: any;
disabled: boolean;
}
import { Tab } from './main_tabs';
import { TabId } from './navigation_menu';

interface Props {
disableLinks: boolean;
tabId: string;
mainTabId: TabId;
tabId: TabId;
}

function getTabs(disableLinks: boolean): Tab[] {
return [
{
id: 'jobs',
name: i18n.translate('xpack.ml.navMenu.jobManagementTabLinkText', {
defaultMessage: 'Job Management',
}),
disabled: disableLinks,
},
{
id: 'explorer',
name: i18n.translate('xpack.ml.navMenu.anomalyExplorerTabLinkText', {
defaultMessage: 'Anomaly Explorer',
}),
disabled: disableLinks,
},
{
id: 'timeseriesexplorer',
name: i18n.translate('xpack.ml.navMenu.singleMetricViewerTabLinkText', {
defaultMessage: 'Single Metric Viewer',
}),
disabled: disableLinks,
},
{
id: 'data_frames',
name: i18n.translate('xpack.ml.navMenu.dataFrameTabLinkText', {
defaultMessage: 'Transforms',
}),
disabled: false,
},
{
id: 'data_frame_analytics',
name: i18n.translate('xpack.ml.navMenu.dataFrameAnalyticsTabLinkText', {
defaultMessage: 'Analytics',
}),
disabled: disableLinks,
},
{
id: 'datavisualizer',
name: i18n.translate('xpack.ml.navMenu.dataVisualizerTabLinkText', {
defaultMessage: 'Data Visualizer',
}),
disabled: false,
},
{
id: 'settings',
name: i18n.translate('xpack.ml.navMenu.settingsTabLinkText', {
defaultMessage: 'Settings',
}),
disabled: disableLinks,
},
];
function getTabs(tabId: TabId, disableLinks: boolean): Tab[] {
const TAB_MAP: Record<TabId, Tab[]> = {
// overview: [],
datavisualizer: [],
data_frames: [],
data_frame_analytics: [],
anomaly_detection: [
{
id: 'jobs',
name: i18n.translate('xpack.ml.navMenu.jobManagementTabLinkText', {
defaultMessage: 'Job Management',
}),
disabled: disableLinks,
},
{
id: 'explorer',
name: i18n.translate('xpack.ml.navMenu.anomalyExplorerTabLinkText', {
defaultMessage: 'Anomaly Explorer',
}),
disabled: disableLinks,
},
{
id: 'timeseriesexplorer',
name: i18n.translate('xpack.ml.navMenu.singleMetricViewerTabLinkText', {
defaultMessage: 'Single Metric Viewer',
}),
disabled: disableLinks,
},
{
id: 'settings',
name: i18n.translate('xpack.ml.navMenu.settingsTabLinkText', {
defaultMessage: 'Settings',
}),
disabled: disableLinks,
},
],
};

return TAB_MAP[tabId];
}

enum TAB_TEST_SUBJECT {
// overview = 'mlOverview',
jobs = 'mlTabJobManagement',
explorer = 'mlTabAnomalyExplorer',
timeseriesexplorer = 'mlTabSingleMetricViewer',
data_frames = 'mlTabDataFrames', // eslint-disable-line
data_frame_analytics = 'mlTabDataFrameAnalytics', // eslint-disable-line
datavisualizer = 'mlTabDataVisualizer',
settings = 'mlTabSettings',
}

type TAB_TEST_SUBJECTS = keyof typeof TAB_TEST_SUBJECT;

export const Tabs: FC<Props> = ({ tabId, disableLinks }) => {
export const Tabs: FC<Props> = ({ tabId, mainTabId, disableLinks }) => {
const [selectedTabId, setSelectedTabId] = useState(tabId);
function onSelectedTabChanged(id: string) {
setSelectedTabId(id);
}

const tabs = getTabs(disableLinks);
const tabs = getTabs(mainTabId, disableLinks);

return (
<EuiTabs>
<EuiTabs size="s" className={tabId === 'settings' ? 'mlSubTabs' : ''}>
{tabs.map((tab: Tab) => {
const id = tab.id;
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function getDataFrameAnalyticsBreadcrumbs() {
ML_BREADCRUMB,
{
text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameLabel', {
defaultMessage: 'Analytics',
defaultMessage: 'Data Frame Analytics',
}),
href: '',
},
Expand Down
4 changes: 2 additions & 2 deletions x-pack/legacy/plugins/ml/public/datavisualizer/breadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
*/

// @ts-ignore
import { ML_BREADCRUMB } from '../breadcrumbs';
import { ML_BREADCRUMB, DATA_VISUALIZER_BREADCRUMB } from '../breadcrumbs';

export function getDataVisualizerBreadcrumbs() {
// Whilst top level nav menu with tabs remains,
// use root ML breadcrumb.
return [ML_BREADCRUMB];
return [ML_BREADCRUMB, DATA_VISUALIZER_BREADCRUMB];
}
Loading

0 comments on commit af52ef0

Please sign in to comment.