Skip to content

Commit 7fc4c29

Browse files
React version of angular license view (#111317)
* React version of angular license view * Fix time handling and linking to license upload * Use getPageData pattern instead of useClusters * Add note about locked time picker * Add disable support to monitoring toolbar * Disable toolbar on license page only * Remove old todo * Clean up render setup method ordering * Fix CI checks Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
1 parent e79a23a commit 7fc4c29

File tree

5 files changed

+132
-5
lines changed

5 files changed

+132
-5
lines changed

x-pack/plugins/monitoring/public/application/index.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import ReactDOM from 'react-dom';
1111
import { Route, Switch, Redirect, Router } from 'react-router-dom';
1212
import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public';
1313
import { LoadingPage } from './pages/loading_page';
14+
import { LicensePage } from './pages/license_page';
1415
import { ClusterOverview } from './pages/cluster/overview_page';
1516
import { MonitoringStartPluginDependencies } from '../types';
1617
import { GlobalStateProvider } from './global_state_context';
@@ -53,7 +54,7 @@ const MonitoringApp: React.FC<{
5354
<Route path="/loading" component={LoadingPage} />
5455
<RouteInit
5556
path="/license"
56-
component={License}
57+
component={LicensePage}
5758
codePaths={['all']}
5859
fetchAllClusters={false}
5960
/>
@@ -91,7 +92,3 @@ const NoData: React.FC<{}> = () => {
9192
const Home: React.FC<{}> = () => {
9293
return <div>Home page (Cluster listing)</div>;
9394
};
94-
95-
const License: React.FC<{}> = () => {
96-
return <div>License page</div>;
97-
};
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import React, { useContext, useState, useCallback, useEffect } from 'react';
9+
import { i18n } from '@kbn/i18n';
10+
import moment from 'moment-timezone';
11+
import { PageTemplate } from './page_template';
12+
import { License } from '../../components';
13+
import { GlobalStateContext } from '../global_state_context';
14+
import { CODE_PATH_LICENSE, STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants';
15+
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
16+
import { MonitoringTimeContainer } from './use_monitoring_time';
17+
18+
const CODE_PATHS = [CODE_PATH_LICENSE];
19+
20+
export const LicensePage: React.FC<{}> = () => {
21+
const title = i18n.translate('xpack.monitoring.license.licenseRouteTitle', {
22+
defaultMessage: 'License',
23+
});
24+
25+
const { setIsDisabled } = useContext(MonitoringTimeContainer.Context);
26+
useEffect(() => {
27+
setIsDisabled(true);
28+
return () => {
29+
setIsDisabled(false);
30+
};
31+
}, [setIsDisabled]);
32+
33+
const state = useContext(GlobalStateContext);
34+
const clusterUuid = state.cluster_uuid;
35+
const ccs = state.ccs;
36+
const [clusters, setClusters] = useState([] as any);
37+
38+
const { services } = useKibana<{ data: any }>();
39+
const timezone = services.uiSettings?.get('dateFormat:tz');
40+
const uploadLicensePath = services.application?.getUrlForApp('management', {
41+
path: 'stack/license_management/upload_license',
42+
});
43+
44+
const getPageData = useCallback(async () => {
45+
const bounds = services.data?.query.timefilter.timefilter.getBounds();
46+
let url = '../api/monitoring/v1/clusters';
47+
if (clusterUuid) {
48+
url += `/${clusterUuid}`;
49+
}
50+
51+
try {
52+
const response = await services.http?.fetch(url, {
53+
method: 'POST',
54+
body: JSON.stringify({
55+
ccs,
56+
timeRange: {
57+
min: bounds.min.toISOString(),
58+
max: bounds.max.toISOString(),
59+
},
60+
codePaths: CODE_PATHS,
61+
}),
62+
});
63+
64+
setClusters(formatClusters(response));
65+
} catch (err) {
66+
// TODO handle error
67+
}
68+
}, [ccs, clusterUuid, services.data?.query.timefilter.timefilter, services.http]);
69+
70+
return (
71+
<PageTemplate title={title} pageTitle="" getPageData={getPageData}>
72+
{licenseComponent(clusters, timezone, uploadLicensePath)}
73+
</PageTemplate>
74+
);
75+
};
76+
77+
function licenseComponent(
78+
clusters: any,
79+
timezone: string,
80+
uploadLicensePath: string | undefined
81+
): any {
82+
if (clusters.length) {
83+
const cluster = clusters[0];
84+
const isPrimaryCluster = cluster.isPrimary;
85+
const license = cluster.license;
86+
let expiryDate = license?.expiry_date_in_millis;
87+
88+
if (expiryDate !== undefined) {
89+
expiryDate = formatDateTimeLocal(expiryDate, timezone);
90+
}
91+
92+
const isExpired = Date.now() > expiryDate;
93+
94+
return (
95+
<License
96+
isPrimaryCluster={isPrimaryCluster}
97+
status={license.status}
98+
type={license.type}
99+
isExpired={isExpired}
100+
expiryDate={expiryDate}
101+
uploadLicensePath={uploadLicensePath}
102+
/>
103+
);
104+
} else {
105+
return null;
106+
}
107+
}
108+
109+
// From x-pack/plugins/monitoring/common/formatting.ts with corrected typing
110+
// TODO open github issue to correct other usages
111+
export function formatDateTimeLocal(date: number | Date, timezone: string | null) {
112+
return moment.tz(date, timezone || moment.tz.guess()).format('LL LTS');
113+
}
114+
115+
function formatClusters(clusters: any) {
116+
return clusters.map(formatCluster);
117+
}
118+
119+
function formatCluster(cluster: any) {
120+
if (cluster.cluster_uuid === STANDALONE_CLUSTER_CLUSTER_UUID) {
121+
cluster.cluster_name = 'Standalone Cluster';
122+
}
123+
return cluster;
124+
}

x-pack/plugins/monitoring/public/application/pages/use_monitoring_time.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export const useMonitoringTime = () => {
3434
const [refreshInterval, setRefreshInterval] = useState(value || DEFAULT_REFRESH_INTERVAL_VALUE);
3535
const [isPaused, setIsPaused] = useState(pause || DEFAULT_REFRESH_INTERVAL_PAUSE);
3636
const [currentTimerange, setTimeRange] = useState<TimeOptions>(defaultTimeRange);
37+
const [isDisabled, setIsDisabled] = useState(false);
3738

3839
const handleTimeChange = useCallback(
3940
(start: string, end: string) => {
@@ -50,6 +51,8 @@ export const useMonitoringTime = () => {
5051
refreshInterval,
5152
setIsPaused,
5253
isPaused,
54+
setIsDisabled,
55+
isDisabled,
5356
};
5457
};
5558

x-pack/plugins/monitoring/public/components/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
*/
77

88
export const PageLoading: FunctionComponent<Props>;
9+
export const License: FunctionComponent<Props>;

x-pack/plugins/monitoring/public/components/shared/toolbar.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export const MonitoringToolbar: React.FC<MonitoringToolbarProps> = ({ pageTitle,
3030
refreshInterval,
3131
setIsPaused,
3232
isPaused,
33+
isDisabled,
3334
} = useContext(MonitoringTimeContainer.Context);
3435
const state = useContext(GlobalStateContext);
3536

@@ -85,6 +86,7 @@ export const MonitoringToolbar: React.FC<MonitoringToolbarProps> = ({ pageTitle,
8586
<EuiFlexItem grow={false}>
8687
<div style={{ padding: 8 }}>
8788
<EuiSuperDatePicker
89+
isDisabled={isDisabled}
8890
start={currentTimerange.from}
8991
end={currentTimerange.to}
9092
onTimeChange={onTimeChange}

0 commit comments

Comments
 (0)