Skip to content

Commit

Permalink
[Fleet] Better display of fleet requirements (elastic#65027)
Browse files Browse the repository at this point in the history
  • Loading branch information
nchaulet authored May 4, 2020
1 parent 6ab1b20 commit 5e972e1
Show file tree
Hide file tree
Showing 22 changed files with 309 additions and 91 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/ingest_manager/common/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface IngestManagerConfigType {
};
fleet: {
enabled: boolean;
tlsCheckDisabled: boolean;
defaultOutputHost: string;
kibana: {
host?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@
export interface CreateFleetSetupResponse {
isInitialized: boolean;
}

export interface GetFleetStatusResponse {
isReady: boolean;
missing_requirements: Array<'tls_required' | 'api_keys' | 'fleet_admin_user'>;
}
2 changes: 1 addition & 1 deletion x-pack/plugins/ingest_manager/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"ui": true,
"configPath": ["xpack", "ingestManager"],
"requiredPlugins": ["licensing", "data", "encryptedSavedObjects"],
"optionalPlugins": ["security", "features"]
"optionalPlugins": ["security", "features", "cloud"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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, { useState, useContext, useEffect } from 'react';
import { useConfig } from './use_config';
import { sendGetFleetStatus } from './use_request';
import { GetFleetStatusResponse } from '../types';

interface FleetStatusState {
enabled: boolean;
isLoading: boolean;
isReady: boolean;
missingRequirements?: GetFleetStatusResponse['missing_requirements'];
}

interface FleetStatus extends FleetStatusState {
refresh: () => Promise<void>;
}

const FleetStatusContext = React.createContext<FleetStatus | undefined>(undefined);

export const FleetStatusProvider: React.FC = ({ children }) => {
const config = useConfig();
const [state, setState] = useState<FleetStatusState>({
enabled: config.fleet.enabled,
isLoading: false,
isReady: false,
});
async function sendGetStatus() {
try {
setState(s => ({ ...s, isLoading: true }));
const res = await sendGetFleetStatus();
if (res.error) {
throw res.error;
}

setState(s => ({
...s,
isLoading: false,
isReady: res.data?.isReady ?? false,
missingRequirements: res.data?.missing_requirements,
}));
} catch (error) {
setState(s => ({ ...s, isLoading: true }));
}
}
useEffect(() => {
sendGetStatus();
}, []);

return (
<FleetStatusContext.Provider value={{ ...state, refresh: () => sendGetStatus() }}>
{children}
</FleetStatusContext.Provider>
);
};

export function useFleetStatus(): FleetStatus {
const context = useContext(FleetStatusContext);

if (!context) {
throw new Error('FleetStatusContext not set');
}

return context;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export * from './enrollment_api_keys';
export * from './epm';
export * from './outputs';
export * from './settings';
export * from './setup';
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@
*/

import { sendRequest } from './use_request';
import { setupRouteService } from '../../services';
import { setupRouteService, fleetSetupRouteService } from '../../services';
import { GetFleetStatusResponse } from '../../types';

export const sendSetup = () => {
return sendRequest({
path: setupRouteService.getSetupPath(),
method: 'post',
});
};

export const sendGetFleetStatus = () => {
return sendRequest<GetFleetStatusResponse>({
path: fleetSetupRouteService.getFleetSetupPath(),
method: 'get',
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { IngestManagerOverview, EPMApp, AgentConfigApp, FleetApp, DataStreamApp
import { CoreContext, DepsContext, ConfigContext, setHttpClient, useConfig } from './hooks';
import { PackageInstallProvider } from './sections/epm/hooks';
import { sendSetup } from './hooks/use_request/setup';
import { FleetStatusProvider } from './hooks/use_fleet_status';
import './index.scss';

export interface ProtectedRouteProps extends RouteProps {
Expand Down Expand Up @@ -142,7 +143,9 @@ const IngestManagerApp = ({
<ConfigContext.Provider value={config}>
<EuiThemeProvider darkMode={isDarkMode}>
<PackageInstallProvider notifications={coreStart.notifications}>
<IngestManagerRoutes basepath={basepath} />
<FleetStatusProvider>
<IngestManagerRoutes basepath={basepath} />
</FleetStatusProvider>
</PackageInstallProvider>
</EuiThemeProvider>
</ConfigContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ import {
EuiButtonEmpty,
EuiButton,
EuiFlyoutFooter,
EuiLink,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { AgentConfig } from '../../../../../types';
import { APIKeySelection } from './key_selection';
import { EnrollmentInstructions } from './instructions';
import { useFleetStatus } from '../../../../../hooks/use_fleet_status';
import { useLink } from '../../../../../hooks';
import { FLEET_PATH } from '../../../../../constants';

interface Props {
onClose: () => void;
Expand All @@ -30,8 +34,11 @@ export const AgentEnrollmentFlyout: React.FunctionComponent<Props> = ({
onClose,
agentConfigs = [],
}) => {
const fleetStatus = useFleetStatus();
const [selectedAPIKeyId, setSelectedAPIKeyId] = useState<string | undefined>();

const fleetLink = useLink(FLEET_PATH);

return (
<EuiFlyout onClose={onClose} size="l" maxWidth={640}>
<EuiFlyoutHeader hasBorder aria-labelledby="FleetAgentEnrollmentFlyoutTitle">
Expand All @@ -45,12 +52,33 @@ export const AgentEnrollmentFlyout: React.FunctionComponent<Props> = ({
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<APIKeySelection
agentConfigs={agentConfigs}
onKeyChange={keyId => setSelectedAPIKeyId(keyId)}
/>
<EuiSpacer size="l" />
<EnrollmentInstructions selectedAPIKeyId={selectedAPIKeyId} />
{fleetStatus.isReady ? (
<>
<APIKeySelection
agentConfigs={agentConfigs}
onKeyChange={keyId => setSelectedAPIKeyId(keyId)}
/>
<EuiSpacer size="l" />
<EnrollmentInstructions selectedAPIKeyId={selectedAPIKeyId} />
</>
) : (
<>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.fleetNotInitializedText"
defaultMessage="Fleet needs to be set up before agents can be enrolled. {link}"
values={{
link: (
<EuiLink href={fleetLink}>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.goToFleetButton"
defaultMessage="Go to Fleet."
/>
</EuiLink>
),
}}
/>
</>
)}
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
Expand All @@ -62,14 +90,16 @@ export const AgentEnrollmentFlyout: React.FunctionComponent<Props> = ({
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton fill onClick={onClose}>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.continueButtonLabel"
defaultMessage="Continue"
/>
</EuiButton>
</EuiFlexItem>
{fleetStatus.isReady && (
<EuiFlexItem grow={false}>
<EuiButton fill onClick={onClose}>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.continueButtonLabel"
defaultMessage="Continue"
/>
</EuiButton>
</EuiFlexItem>
)}
</EuiFlexGroup>
</EuiFlyoutFooter>
</EuiFlyout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,31 @@
import React from 'react';
import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
import { Loading } from '../../components';
import { useConfig, useCore, useRequest } from '../../hooks';
import { useConfig, useCore } from '../../hooks';
import { AgentListPage } from './agent_list_page';
import { SetupPage } from './setup_page';
import { AgentDetailsPage } from './agent_details_page';
import { NoAccessPage } from './error_pages/no_access';
import { fleetSetupRouteService } from '../../services';
import { EnrollmentTokenListPage } from './enrollment_token_list_page';
import { ListLayout } from './components/list_layout';
import { useFleetStatus } from '../../hooks/use_fleet_status';

export const FleetApp: React.FunctionComponent = () => {
const core = useCore();
const { fleet } = useConfig();

const setupRequest = useRequest({
method: 'get',
path: fleetSetupRouteService.getFleetSetupPath(),
});
const fleetStatus = useFleetStatus();

if (!fleet.enabled) return null;
if (setupRequest.isLoading) {
if (fleetStatus.isLoading) {
return <Loading />;
}

if (setupRequest.data.isInitialized === false) {
if (fleetStatus.isReady === false) {
return (
<SetupPage
refresh={async () => {
await setupRequest.sendRequest();
}}
missingRequirements={fleetStatus.missingRequirements || []}
refresh={fleetStatus.refresh}
/>
);
}
Expand Down
Loading

0 comments on commit 5e972e1

Please sign in to comment.