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] Migrate to React BrowserRouter and Kibana provided History. #71941

Merged
merged 37 commits into from
Jul 31, 2020
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3301ff5
[ML] Migrate to React BrowserRouter and Kibana provided History.
walterra Jul 15, 2020
2cb3f93
Merge branch 'master' into ml-migrate-router
walterra Jul 16, 2020
b8e6abf
[ML] Fixes redirects and adds comments for router related components.
walterra Jul 16, 2020
686e6d8
[ML] Pass history on as part of PageDependencies.
walterra Jul 16, 2020
2c02364
[ML] Use useEffect for legacy redirect.
walterra Jul 16, 2020
635e32e
[ML] Migrate breadcrumbs away from hash based urls.
walterra Jul 16, 2020
85fec20
[ML] Fixes breadcrumb full refreshes.
walterra Jul 16, 2020
1d9c8b4
[ML] Fixes job creation card navigation.
walterra Jul 16, 2020
38994c1
[ML] Fix translations.
walterra Jul 17, 2020
4859521
Merge branch 'master' into ml-migrate-router
walterra Jul 17, 2020
9580a79
[ML] Fix job creation button.
walterra Jul 17, 2020
fad85ec
[ML] Introduces useNavigateToPath().
walterra Jul 17, 2020
0cae8a1
[ML] Fix data visualizer navigation.
walterra Jul 17, 2020
7afef2b
Merge branch 'master' into ml-migrate-router
walterra Jul 17, 2020
7cf3944
Merge branch 'master' into ml-migrate-router
walterra Jul 27, 2020
8907a16
[ML] Fix anomaly detection wizard url params.
walterra Jul 27, 2020
44cc53b
[ML] Fix hash position.
walterra Jul 27, 2020
24bc277
Merge branch 'master' into ml-migrate-router
walterra Jul 28, 2020
4cd358b
[ML] Fix anomaly detection wizard navigation.
walterra Jul 28, 2020
748cb71
Merge branch 'master' into ml-migrate-router
walterra Jul 29, 2020
6d9b6f2
[ML] Fix opening of custom URLs with relative paths.
walterra Jul 29, 2020
4a12842
[ML] Add jest tests for openCustomUrlWindow().
walterra Jul 29, 2020
d069fa7
Merge branch 'master' into ml-migrate-router
walterra Jul 29, 2020
95eccbe
[ML] Delete unused code.
walterra Jul 29, 2020
909b7ae
[ML] Fix link to calendars list.
walterra Jul 29, 2020
5cfa29a
Merge branch 'master' into ml-migrate-router
walterra Jul 29, 2020
7c43179
Merge branch 'master' into ml-migrate-router
walterra Jul 29, 2020
ed7d8d7
[ML] Tweak button code.
walterra Jul 29, 2020
8ddbc80
Merge branch 'master' into ml-migrate-router
elasticmachine Jul 30, 2020
ab504a5
Merge branch 'master' into ml-migrate-router
walterra Jul 30, 2020
1e64ab3
[ML] Add security to isKibanaUrl check.
walterra Jul 30, 2020
d329b40
Merge branch 'ml-migrate-router' of github.com:walterra/kibana into m…
walterra Jul 30, 2020
a4e5a2b
[ML] Fix security link.
walterra Jul 30, 2020
b7248f5
[Ml] Add legacy SIEM link to isKibanaUrl().
walterra Jul 30, 2020
dbce65d
Merge branch 'master' into ml-migrate-router
elasticmachine Jul 30, 2020
12afcba
Merge branch 'master' into ml-migrate-router
elasticmachine Jul 30, 2020
f2c47e3
Merge branch 'master' into ml-migrate-router
elasticmachine Jul 30, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions x-pack/plugins/ml/public/application/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type MlDependencies = Omit<MlSetupDependencies, 'share'> & MlStartDepende
interface AppProps {
coreStart: CoreStart;
deps: MlDependencies;
appMountParams: AppMountParameters;
}

const localStorage = new Storage(window.localStorage);
Expand All @@ -46,8 +47,9 @@ export interface MlServicesContext {

export type MlGlobalServices = ReturnType<typeof getMlGlobalServices>;

const App: FC<AppProps> = ({ coreStart, deps }) => {
const App: FC<AppProps> = ({ coreStart, deps, appMountParams }) => {
const pageDeps = {
history: appMountParams.history,
indexPatterns: deps.data.indexPatterns,
config: coreStart.uiSettings!,
setBreadcrumbs: coreStart.chrome!.setBreadcrumbs,
Expand Down Expand Up @@ -104,7 +106,11 @@ export const renderApp = (
appMountParams.onAppLeave((actions) => actions.default());

const mlLicense = setLicenseCache(deps.licensing, [
() => ReactDOM.render(<App coreStart={coreStart} deps={deps} />, appMountParams.element),
() =>
ReactDOM.render(
<App coreStart={coreStart} deps={deps} appMountParams={appMountParams} />,
appMountParams.element
),
]);

return () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
*/

import { i18n } from '@kbn/i18n';

import { ApplicationStart } from 'kibana/public';

import { Job, Datafeed, Detector } from '../../../../../../../common/types/anomaly_detection_jobs';
import { newJobCapsService } from '../../../../../services/new_job_capabilities_service';
import {
Expand Down Expand Up @@ -258,7 +261,10 @@ export function convertToMultiMetricJob(jobCreator: JobCreatorType) {
);
}

export function convertToAdvancedJob(jobCreator: JobCreatorType) {
export function convertToAdvancedJob(
jobCreator: JobCreatorType,
{ getUrlForApp, navigateToUrl }: ApplicationStart
) {
jobCreator.createdBy = null;
stashCombinedJob(jobCreator, true, true);

Expand All @@ -271,19 +277,27 @@ export function convertToAdvancedJob(jobCreator: JobCreatorType) {
jobType = JOB_TYPE.CATEGORIZATION;
}

window.location.href = window.location.href.replace(jobType, JOB_TYPE.ADVANCED);
navigateToUrl(
getUrlForApp('ml', { path: window.location.href.replace(jobType, JOB_TYPE.ADVANCED) })
);
}

export function resetJob(jobCreator: JobCreatorType) {
export function resetJob(
jobCreator: JobCreatorType,
{ getUrlForApp, navigateToUrl }: ApplicationStart
) {
jobCreator.jobId = '';
stashCombinedJob(jobCreator, true, true);

window.location.href = '#/jobs/new_job';
navigateToUrl(getUrlForApp('ml', { path: '/jobs/new_job' }));
}

export function advancedStartDatafeed(jobCreator: JobCreatorType) {
export function advancedStartDatafeed(
jobCreator: JobCreatorType,
{ getUrlForApp, navigateToUrl }: ApplicationStart
) {
stashCombinedJob(jobCreator, false, false);
window.location.href = '#/jobs';
navigateToUrl(getUrlForApp('ml', { path: '/jobs' }));
}

export function aggFieldPairsCanBeCharted(afs: AggFieldPair[]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import { JobSectionTitle, DatafeedSectionTitle } from './components/common';

export const SummaryStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep }) => {
const {
services: { notifications },
services: { application, notifications },
} = useMlKibana();
const { jobCreator, jobValidator, jobValidatorUpdated, resultsLoader } = useContext(
JobCreatorContext
Expand Down Expand Up @@ -87,7 +87,7 @@ export const SummaryStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep }) =>
try {
await jobCreator.createJob();
await jobCreator.createDatafeed();
advancedStartDatafeed(jobCreator);
advancedStartDatafeed(jobCreator, application);
} catch (error) {
// catch and display all job creation errors
const { toasts } = notifications;
Expand All @@ -112,11 +112,11 @@ export const SummaryStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep }) =>
}

function clickResetJob() {
resetJob(jobCreator);
resetJob(jobCreator, application);
}

const convertToAdvanced = () => {
convertToAdvancedJob(jobCreator);
convertToAdvancedJob(jobCreator, application);
};

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
EuiLink,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { useMlKibana } from '../../../../contexts/kibana';
import { useMlContext } from '../../../../contexts/ml';
import { isSavedSearchSavedObject } from '../../../../../../common/types/kibana';
import { DataRecognizer } from '../../../../components/data_recognizer';
Expand All @@ -27,6 +28,11 @@ import { CreateJobLinkCard } from '../../../../components/create_job_link_card';
import { CategorizationIcon } from './categorization_job_icon';

export const Page: FC = () => {
const {
services: {
application: { getUrlForApp, navigateToUrl },
},
} = useMlKibana();
const mlContext = useMlContext();
const [recognizerResultsCount, setRecognizerResultsCount] = useState(0);

Expand Down Expand Up @@ -68,25 +74,27 @@ export const Page: FC = () => {
},
};

const getUrl = (basePath: string) => {
const getUrlParams = () => {
return !isSavedSearchSavedObject(currentSavedSearch)
? `${basePath}?index=${currentIndexPattern.id}`
: `${basePath}?savedSearchId=${currentSavedSearch.id}`;
? `?index=${currentIndexPattern.id}`
: `?savedSearchId=${currentSavedSearch.id}`;
};

const navigateToPath = (path: string | undefined) =>
navigateToUrl(getUrlForApp('ml', { path: `${path}${getUrlParams()}` }));
Copy link
Member

@jgowdyelastic jgowdyelastic Jul 17, 2020

Choose a reason for hiding this comment

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

seeing as we use this function combination a lot, could this be wrapped in a provider function that just takes the path and supplied by useMlContext ?
it should also use PLUGIN_ID from kibana/x-pack/plugins/ml/common/constants/app.ts

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed, decided to do it in this PR, we now have useNavigateToPath() based on useMlContext(), available via contexts/kibana. Update in fad85ec.


const addSelectionToRecentlyAccessed = () => {
const title = !isSavedSearchSavedObject(currentSavedSearch)
? currentIndexPattern.title
: (currentSavedSearch.attributes.title as string);
const url = getUrl('');
const url = getUrlForApp('ml', { path: '' });
addItemToRecentlyAccessed('jobs/new_job/datavisualizer', title, url);

window.location.href = getUrl('#jobs/new_job/datavisualizer');
navigateToPath('/jobs/new_job/datavisualizer');
};

const jobTypes = [
{
href: getUrl('#jobs/new_job/single_metric'),
onClick: () => navigateToPath('/jobs/new_job/single_metric'),
icon: {
type: 'createSingleMetricJob',
ariaLabel: i18n.translate('xpack.ml.newJob.wizard.jobType.singleMetricAriaLabel', {
Expand All @@ -102,7 +110,7 @@ export const Page: FC = () => {
id: 'mlJobTypeLinkSingleMetricJob',
},
{
href: getUrl('#jobs/new_job/multi_metric'),
onClick: () => navigateToPath('/jobs/new_job/multi_metric'),
icon: {
type: 'createMultiMetricJob',
ariaLabel: i18n.translate('xpack.ml.newJob.wizard.jobType.multiMetricAriaLabel', {
Expand All @@ -119,7 +127,7 @@ export const Page: FC = () => {
id: 'mlJobTypeLinkMultiMetricJob',
},
{
href: getUrl('#jobs/new_job/population'),
onClick: () => navigateToPath('/jobs/new_job/population'),
icon: {
type: 'createPopulationJob',
ariaLabel: i18n.translate('xpack.ml.newJob.wizard.jobType.populationAriaLabel', {
Expand All @@ -136,7 +144,7 @@ export const Page: FC = () => {
id: 'mlJobTypeLinkPopulationJob',
},
{
href: getUrl('#jobs/new_job/advanced'),
onClick: () => navigateToPath('/jobs/new_job/advanced'),
icon: {
type: 'createAdvancedJob',
ariaLabel: i18n.translate('xpack.ml.newJob.wizard.jobType.advancedAriaLabel', {
Expand All @@ -153,7 +161,7 @@ export const Page: FC = () => {
id: 'mlJobTypeLinkAdvancedJob',
},
{
href: getUrl('#jobs/new_job/categorization'),
onClick: () => navigateToPath('/jobs/new_job/categorization'),
icon: {
type: CategorizationIcon,
ariaLabel: i18n.translate('xpack.ml.newJob.wizard.jobType.categorizationAriaLabel', {
Expand Down Expand Up @@ -247,11 +255,11 @@ export const Page: FC = () => {
<EuiSpacer size="m" />

<EuiFlexGrid gutterSize="l" columns={4}>
{jobTypes.map(({ href, icon, title, description, id }) => (
{jobTypes.map(({ onClick, icon, title, description, id }) => (
<EuiFlexItem key={id}>
<CreateJobLinkCard
data-test-subj={id}
href={href}
onClick={onClick}
icon={icon.type}
iconAreaLabel={icon.ariaLabel}
title={title}
Expand Down Expand Up @@ -307,7 +315,6 @@ export const Page: FC = () => {
/>
}
onClick={addSelectionToRecentlyAccessed}
href={getUrl('#jobs/new_job/datavisualizer')}
/>
</EuiFlexItem>
</EuiFlexGrid>
Expand Down
49 changes: 41 additions & 8 deletions x-pack/plugins/ml/public/application/routing/breadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,80 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { EuiBreadcrumb } from '@elastic/eui';

import { i18n } from '@kbn/i18n';
import { ChromeBreadcrumb } from 'kibana/public';

import { ApplicationStart, ChromeBreadcrumb } from 'kibana/public';

export const ML_BREADCRUMB: ChromeBreadcrumb = Object.freeze({
text: i18n.translate('xpack.ml.machineLearningBreadcrumbLabel', {
defaultMessage: 'Machine Learning',
}),
href: '#/',
href: '/',
});

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

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

export const DATA_FRAME_ANALYTICS_BREADCRUMB: ChromeBreadcrumb = Object.freeze({
text: i18n.translate('xpack.ml.dataFrameAnalyticsLabel', {
defaultMessage: 'Data Frame Analytics',
}),
href: '#/data_frame_analytics',
href: '/data_frame_analytics',
});

export const DATA_VISUALIZER_BREADCRUMB: ChromeBreadcrumb = Object.freeze({
text: i18n.translate('xpack.ml.datavisualizerBreadcrumbLabel', {
defaultMessage: 'Data Visualizer',
}),
href: '#/datavisualizer',
href: '/datavisualizer',
});

export const CREATE_JOB_BREADCRUMB: ChromeBreadcrumb = Object.freeze({
text: i18n.translate('xpack.ml.createJobsBreadcrumbLabel', {
defaultMessage: 'Create job',
}),
href: '#/jobs/new_job',
href: '/jobs/new_job',
});

const breadcrumbs = {
ML_BREADCRUMB,
SETTINGS_BREADCRUMB,
ANOMALY_DETECTION_BREADCRUMB,
DATA_FRAME_ANALYTICS_BREADCRUMB,
DATA_VISUALIZER_BREADCRUMB,
CREATE_JOB_BREADCRUMB,
};
type Breadcrumb = keyof typeof breadcrumbs;

export const breadcrumbOnClickFactory = (
path: string | undefined,
{ getUrlForApp, navigateToUrl }: ApplicationStart
): EuiBreadcrumb['onClick'] => {
return (e) => {
e.preventDefault();
navigateToUrl(getUrlForApp('ml', { path }));
};
};

export const getBreadcrumbWithUrlForApp = (
breadcrumbName: Breadcrumb,
application: ApplicationStart
): EuiBreadcrumb => {
return {
...breadcrumbs[breadcrumbName],
onClick: breadcrumbOnClickFactory(breadcrumbs[breadcrumbName].href, application),
};
};
Loading