Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ML] Kibana Management Jobs list: Ensure proper title, tagline, and link to documentation #43418

Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ interface Props {
isManagementTable?: boolean;
}
// isManagementTable - for use in Kibana managagement ML section
export const DataFrameAnalyticsList: FC<Props> = ({ isManagementTable }) => {
export const DataFrameAnalyticsList: FC<Props> = ({ isManagementTable = false }) => {
const [isInitialized, setIsInitialized] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [blockRefresh, setBlockRefresh] = useState(false);
Expand Down Expand Up @@ -101,8 +101,11 @@ export const DataFrameAnalyticsList: FC<Props> = ({ isManagementTable }) => {
isLoading: setIsLoading,
onRefresh: () => getAnalytics(true),
});
// Call useRefreshInterval() after the subscription above is set up.
useRefreshInterval(setBlockRefresh);

if (isManagementTable === false) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hooks need to be at the top level, we cannot put them inside conditions unfortunately https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level.

Maybe an alternative is to pass isManagementTable on to the hook and act on it there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense normally, but in this case isManagementTable value is never changing so it wouldn't change the order of the hooks being called. 🤔
I'm happy to change it though since maybe it does set an example for a pattern we wouldn't want to follow most of the time.

// Call useRefreshInterval() after the subscription above is set up.
useRefreshInterval(setBlockRefresh);
}

const onQueryChange = ({ query, error }: { query: Query; error: any }) => {
if (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export const getColumns = (
name: 'ID',
sortable: true,
truncateText: true,
width: isManagementTable === true ? '20%' : undefined,
},
// Description is not supported yet by API
/*
Expand All @@ -124,6 +125,7 @@ export const getColumns = (
}),
sortable: true,
truncateText: true,
width: isManagementTable === true ? '25%' : undefined,
},
{
field: DataFrameAnalyticsListColumn.configDestIndex,
Expand All @@ -132,6 +134,7 @@ export const getColumns = (
}),
sortable: true,
truncateText: true,
width: isManagementTable === true ? '20%' : undefined,
},
{
name: i18n.translate('xpack.ml.dataframe.analyticsList.status', { defaultMessage: 'Status' }),
Expand Down Expand Up @@ -208,7 +211,14 @@ export const getColumns = (
},
];

if (isManagementTable === false) {
if (isManagementTable === true) {
columns.push({
name: i18n.translate('xpack.ml.jobsList.analyticsSpacesLabel', {
defaultMessage: 'Spaces',
}),
render: () => <EuiBadge color={'hollow'}>{'all'}</EuiBadge>,
});
} else {
columns.push({
name: i18n.translate('xpack.ml.dataframe.analyticsList.tableActionLabel', {
defaultMessage: 'Actions',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,25 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { FC } from 'react';
import React, { FC, useState } from 'react';

import { EuiButtonEmpty } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { useRefreshAnalyticsList } from '../../../../common';

interface RefreshAnalyticsListButtonProps {
isLoading: boolean;
onClick(): void;
}
export const RefreshAnalyticsListButton: FC<RefreshAnalyticsListButtonProps> = ({
onClick,
isLoading,
}) => (
<EuiButtonEmpty
data-test-subj="mlRefreshAnalyticsListButton"
onClick={onClick}
isLoading={isLoading}
>
<FormattedMessage
id="xpack.ml.dataframe.analyticsList.refreshButtonLabel"
defaultMessage="Refresh"
/>
</EuiButtonEmpty>
);
export const RefreshAnalyticsListButton: FC = () => {
const [isLoading, setIsLoading] = useState(false);
const { refresh } = useRefreshAnalyticsList({ isLoading: setIsLoading });
return (
<EuiButtonEmpty
data-test-subj="mlRefreshAnalyticsListButton"
onClick={refresh}
isLoading={isLoading}
>
<FormattedMessage
id="xpack.ml.dataframe.analyticsList.refreshButtonLabel"
defaultMessage="Refresh"
/>
</EuiButtonEmpty>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { Fragment, FC, useState } from 'react';
import React, { Fragment, FC } from 'react';

import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
Expand All @@ -24,15 +24,11 @@ import {
} from '@elastic/eui';

import { NavigationMenu } from '../../../components/navigation_menu/navigation_menu';
import { useRefreshAnalyticsList } from '../../common';
import { CreateAnalyticsButton } from './components/create_analytics_button';
import { DataFrameAnalyticsList } from './components/analytics_list';
import { RefreshAnalyticsListButton } from './components/refresh_analytics_list_button';

export const Page: FC = () => {
const [isLoading, setIsLoading] = useState(false);
const { refresh } = useRefreshAnalyticsList({ isLoading: setIsLoading });

return (
<Fragment>
<NavigationMenu tabId="data_frame_analytics" />
Expand Down Expand Up @@ -68,7 +64,7 @@ export const Page: FC = () => {
<EuiFlexGroup alignItems="center">
{/* grow={false} fixes IE11 issue with nested flex */}
<EuiFlexItem grow={false}>
{<RefreshAnalyticsListButton onClick={refresh} isLoading={isLoading} />}
<RefreshAnalyticsListButton />
</EuiFlexItem>
{/* grow={false} fixes IE11 issue with nested flex */}
<EuiFlexItem grow={false}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,11 @@
.mlTaskStateBadge {
max-width: 100px;
}

.mlKibanaManagement__analyticsSpacer {
clear: both;
}

.mlKibanaManagement__analyticsRefreshButton {
float: right;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,38 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { Fragment, FC } from 'react';
import React, { Fragment, FC, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { I18nContext } from 'ui/i18n';
import {
EuiButtonEmpty,
EuiFlexGroup,
EuiFlexItem,
EuiPageContent,
EuiPageContentBody,
EuiPageContentHeader,
EuiPageContentHeaderSection,
EuiSpacer,
EuiTabbedContent,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { metadata } from 'ui/metadata';

// @ts-ignore undeclared module
import { JobsListView } from '../../../../jobs/jobs_list/components/jobs_list_view';
import { DataFrameAnalyticsList } from '../../../../data_frame_analytics/pages/analytics_management/components/analytics_list';
import { RefreshAnalyticsListButton } from '../../../../data_frame_analytics/pages/analytics_management/components/refresh_analytics_list_button';

interface Props {
isMlEnabledInSpace: boolean;
}
interface Tab {
id: string;
name: string;
content: any;
}

export const JobsListPage: FC<Props> = ({ isMlEnabledInSpace }) => {
const tabs = [
function getTabs(isMlEnabledInSpace: boolean): Tab[] {
return [
{
id: 'anomaly_detection_jobs',
name: i18n.translate('xpack.ml.management.jobsList.anomalyDetectionTab', {
Expand All @@ -47,30 +56,88 @@ export const JobsListPage: FC<Props> = ({ isMlEnabledInSpace }) => {
content: (
<Fragment>
<EuiSpacer size="m" />
<span className="mlKibanaManagement__analyticsRefreshButton">
<RefreshAnalyticsListButton />
</span>
<EuiSpacer size="s" className="mlKibanaManagement__analyticsSpacer" />
<DataFrameAnalyticsList isManagementTable={true} />
</Fragment>
),
},
];
}

export const JobsListPage: FC<Props> = ({ isMlEnabledInSpace }) => {
const tabs = getTabs(isMlEnabledInSpace);
const [currentTabId, setCurrentTabId] = useState(tabs[0].id);

// metadata.branch corresponds to the version used in documentation links.
const anomalyDetectionJobsUrl = `https://www.elastic.co/guide/en/elastic-stack-overview/${metadata.branch}/ml-jobs.html`;
const anomalyJobsUrl = `https://www.elastic.co/guide/en/elastic-stack-overview/${metadata.branch}/ml-dfanalytics.html`;

const anomalyDetectionDocsLabel = i18n.translate(
'xpack.ml.management.jobsList.anomalyDetectionDocsLabel',
{
defaultMessage: 'Anomaly detection jobs docs',
}
);
const analyticsDocsLabel = i18n.translate('xpack.ml.management.jobsList.analyticsDocsLabel', {
defaultMessage: 'Analytics jobs docs',
});

function renderTabs() {
return <EuiTabbedContent size="s" tabs={tabs} initialSelectedTab={tabs[0]} />;
return (
<EuiTabbedContent
onTabClick={({ id }: { id: string }) => {
setCurrentTabId(id);
}}
size="s"
tabs={getTabs(isMlEnabledInSpace)}
initialSelectedTab={tabs[0]}
/>
);
}

return (
<I18nContext>
<EuiPageContent>
<EuiPageContentHeader>
<EuiPageContentHeaderSection>
<EuiTitle>
<h2>
<EuiTitle size="l">
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<h1>
{i18n.translate('xpack.ml.management.jobsList.jobsListTitle', {
defaultMessage: 'Jobs',
defaultMessage: 'Machine Learning Jobs',
})}
</h2>
</EuiTitle>
</EuiPageContentHeaderSection>
</EuiPageContentHeader>
</h1>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
target="_blank"
iconType="help"
iconSide="left"
color="primary"
href={
currentTabId === 'anomaly_detection_jobs'
? anomalyDetectionJobsUrl
: anomalyJobsUrl
}
>
{currentTabId === 'anomaly_detection_jobs'
? anomalyDetectionDocsLabel
: analyticsDocsLabel}
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiTitle>
<EuiSpacer size="s" />
<EuiTitle size="s">
<EuiText color="subdued">
{i18n.translate('xpack.ml.management.jobsList.jobsListTagline', {
defaultMessage: 'View machine learning analytics and anomaly detection jobs.',
})}
</EuiText>
</EuiTitle>
<EuiSpacer size="l" />
<EuiPageContentBody>{renderTabs()}</EuiPageContentBody>
</EuiPageContent>
</I18nContext>
Expand Down