-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Fleet] Support for showing an Integration Detail Custom (UI Extension) tab #83805
Merged
paul-tavares
merged 25 commits into
elastic:master
from
paul-tavares:task/fleet-82492-integration-custom-tab
Nov 30, 2020
Merged
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
c8c3c5d
Support for rendering a custom component in Integration Details
paul-tavares e2e51c9
Refactor Fleet app initialization contexts in order to support testin…
paul-tavares 9d4afc5
Initial implementation of test rendering helper tool
paul-tavares 82a475f
adjust order of contexts to match prior implementation
paul-tavares df94c92
more specific implementation around custom tab component
paul-tavares 028e0e1
Plugin dependencies mocks + renaming + expose mocks for other plugins
paul-tavares 8bba5d1
refactor Endpoint to use mock builder from ingest
paul-tavares d6e106c
Merge remote-tracking branch 'upstream/master' into task/fleet-82485-…
paul-tavares 88784fb
Fix plugin.ts after merge from master
paul-tavares 4bd5c75
Adjustment to test renderer to use values from returned object during…
paul-tavares 60a7ff3
More fixes after merge from master
paul-tavares 333c10e
Additional fixes after master merge (jen's changes)
paul-tavares 80a5e96
Initial test file for Integration details
paul-tavares 94f0c01
Merge remote-tracking branch 'upstream/master' into task/fleet-82492-…
paul-tavares e6e8eb9
apply feedback from prior code review
paul-tavares d013587
Refactor FleetStartServices mock
paul-tavares b29029a
Fix TestRender's history instance due to use of Hash Router
paul-tavares 4b31a39
Merge remote-tracking branch 'upstream/master' into task/fleet-82492-…
paul-tavares 789ad25
Fixed some left over types
paul-tavares ae81b29
Fix eslint issue
paul-tavares 495fbbd
Merge remote-tracking branch 'upstream/master' into task/fleet-82492-…
paul-tavares 8fba859
remove ts-ignore
paul-tavares b3ddc2f
some more tests
paul-tavares 093fecb
Complete test cases for custom tab in integrations
paul-tavares 630f7c2
Merge remote-tracking branch 'upstream/master' into task/fleet-82492-…
paul-tavares File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
/* | ||
* 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, { memo, useEffect, useState } from 'react'; | ||
import { AppMountParameters } from 'kibana/public'; | ||
import { EuiCode, EuiEmptyPrompt, EuiErrorBoundary, EuiPanel } from '@elastic/eui'; | ||
import { createHashHistory, History } from 'history'; | ||
import { Router, Redirect, Route, Switch } from 'react-router-dom'; | ||
import { FormattedMessage } from '@kbn/i18n/react'; | ||
import { i18n } from '@kbn/i18n'; | ||
import styled from 'styled-components'; | ||
import useObservable from 'react-use/lib/useObservable'; | ||
import { | ||
ConfigContext, | ||
FleetStatusProvider, | ||
KibanaVersionContext, | ||
sendGetPermissionsCheck, | ||
sendSetup, | ||
useBreadcrumbs, | ||
useConfig, | ||
} from './hooks'; | ||
import { Error, Loading } from './components'; | ||
import { IntraAppStateProvider } from './hooks/use_intra_app_state'; | ||
import { PackageInstallProvider } from './sections/epm/hooks'; | ||
import { PAGE_ROUTING_PATHS } from './constants'; | ||
import { DefaultLayout, WithoutHeaderLayout } from './layouts'; | ||
import { EPMApp } from './sections/epm'; | ||
import { AgentPolicyApp } from './sections/agent_policy'; | ||
import { DataStreamApp } from './sections/data_stream'; | ||
import { FleetApp } from './sections/agents'; | ||
import { IngestManagerOverview } from './sections/overview'; | ||
import { ProtectedRoute } from './index'; | ||
import { FleetConfigType, FleetStartServices } from '../../plugin'; | ||
import { UIExtensionsStorage } from './types'; | ||
import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; | ||
import { EuiThemeProvider } from '../../../../xpack_legacy/common'; | ||
import { UIExtensionsContext } from './hooks/use_ui_extension'; | ||
|
||
const ErrorLayout = ({ children }: { children: JSX.Element }) => ( | ||
<EuiErrorBoundary> | ||
<DefaultLayout showSettings={false}> | ||
<WithoutHeaderLayout>{children}</WithoutHeaderLayout> | ||
</DefaultLayout> | ||
</EuiErrorBoundary> | ||
); | ||
|
||
const Panel = styled(EuiPanel)` | ||
max-width: 500px; | ||
margin-right: auto; | ||
margin-left: auto; | ||
`; | ||
|
||
export const WithPermissionsAndSetup: React.FC = memo(({ children }) => { | ||
useBreadcrumbs('base'); | ||
|
||
const [isPermissionsLoading, setIsPermissionsLoading] = useState<boolean>(false); | ||
const [permissionsError, setPermissionsError] = useState<string>(); | ||
const [isInitialized, setIsInitialized] = useState(false); | ||
const [initializationError, setInitializationError] = useState<Error | null>(null); | ||
|
||
useEffect(() => { | ||
(async () => { | ||
setIsPermissionsLoading(false); | ||
setPermissionsError(undefined); | ||
setIsInitialized(false); | ||
setInitializationError(null); | ||
try { | ||
setIsPermissionsLoading(true); | ||
const permissionsResponse = await sendGetPermissionsCheck(); | ||
setIsPermissionsLoading(false); | ||
if (permissionsResponse.data?.success) { | ||
try { | ||
const setupResponse = await sendSetup(); | ||
if (setupResponse.error) { | ||
setInitializationError(setupResponse.error); | ||
} | ||
} catch (err) { | ||
setInitializationError(err); | ||
} | ||
setIsInitialized(true); | ||
} else { | ||
setPermissionsError(permissionsResponse.data?.error || 'REQUEST_ERROR'); | ||
} | ||
} catch (err) { | ||
setPermissionsError('REQUEST_ERROR'); | ||
} | ||
})(); | ||
}, []); | ||
|
||
if (isPermissionsLoading || permissionsError) { | ||
return ( | ||
<ErrorLayout> | ||
{isPermissionsLoading ? ( | ||
<Loading /> | ||
) : permissionsError === 'REQUEST_ERROR' ? ( | ||
<Error | ||
title={ | ||
<FormattedMessage | ||
id="xpack.fleet.permissionsRequestErrorMessageTitle" | ||
defaultMessage="Unable to check permissions" | ||
/> | ||
} | ||
error={i18n.translate('xpack.fleet.permissionsRequestErrorMessageDescription', { | ||
defaultMessage: 'There was a problem checking Fleet permissions', | ||
})} | ||
/> | ||
) : ( | ||
<Panel> | ||
<EuiEmptyPrompt | ||
iconType="securityApp" | ||
title={ | ||
<h2> | ||
{permissionsError === 'MISSING_SUPERUSER_ROLE' ? ( | ||
<FormattedMessage | ||
id="xpack.fleet.permissionDeniedErrorTitle" | ||
defaultMessage="Permission denied" | ||
/> | ||
) : ( | ||
<FormattedMessage | ||
id="xpack.fleet.securityRequiredErrorTitle" | ||
defaultMessage="Security is not enabled" | ||
/> | ||
)} | ||
</h2> | ||
} | ||
body={ | ||
<p> | ||
{permissionsError === 'MISSING_SUPERUSER_ROLE' ? ( | ||
<FormattedMessage | ||
id="xpack.fleet.permissionDeniedErrorMessage" | ||
defaultMessage="You are not authorized to access Fleet. Fleet requires {roleName} privileges." | ||
values={{ roleName: <EuiCode>superuser</EuiCode> }} | ||
/> | ||
) : ( | ||
<FormattedMessage | ||
id="xpack.fleet.securityRequiredErrorMessage" | ||
defaultMessage="You must enable security in Kibana and Elasticsearch to use Fleet." | ||
/> | ||
)} | ||
</p> | ||
} | ||
/> | ||
</Panel> | ||
)} | ||
</ErrorLayout> | ||
); | ||
} | ||
|
||
if (!isInitialized || initializationError) { | ||
return ( | ||
<ErrorLayout> | ||
{initializationError ? ( | ||
<Error | ||
title={ | ||
<FormattedMessage | ||
id="xpack.fleet.initializationErrorMessageTitle" | ||
defaultMessage="Unable to initialize Fleet" | ||
/> | ||
} | ||
error={initializationError} | ||
/> | ||
) : ( | ||
<Loading /> | ||
)} | ||
</ErrorLayout> | ||
); | ||
} | ||
|
||
return <>{children}</>; | ||
}); | ||
|
||
/** | ||
* Fleet Application context all the way down to the Router, but with no permissions or setup checks | ||
* and no routes defined | ||
*/ | ||
export const FleetAppContext: React.FC<{ | ||
basepath: string; | ||
startServices: FleetStartServices; | ||
config: FleetConfigType; | ||
history: AppMountParameters['history']; | ||
kibanaVersion: string; | ||
extensions: UIExtensionsStorage; | ||
/** For testing purposes only */ | ||
routerHistory?: History<any>; | ||
}> = memo( | ||
({ | ||
children, | ||
startServices, | ||
config, | ||
history, | ||
kibanaVersion, | ||
extensions, | ||
routerHistory = createHashHistory(), | ||
}) => { | ||
const isDarkMode = useObservable<boolean>(startServices.uiSettings.get$('theme:darkMode')); | ||
|
||
return ( | ||
<startServices.i18n.Context> | ||
<KibanaContextProvider services={{ ...startServices }}> | ||
<EuiErrorBoundary> | ||
<ConfigContext.Provider value={config}> | ||
<KibanaVersionContext.Provider value={kibanaVersion}> | ||
<EuiThemeProvider darkMode={isDarkMode}> | ||
<UIExtensionsContext.Provider value={extensions}> | ||
<FleetStatusProvider> | ||
<IntraAppStateProvider kibanaScopedHistory={history}> | ||
<Router history={routerHistory}> | ||
<PackageInstallProvider notifications={startServices.notifications}> | ||
{children} | ||
</PackageInstallProvider> | ||
</Router> | ||
</IntraAppStateProvider> | ||
</FleetStatusProvider> | ||
</UIExtensionsContext.Provider> | ||
</EuiThemeProvider> | ||
</KibanaVersionContext.Provider> | ||
</ConfigContext.Provider> | ||
</EuiErrorBoundary> | ||
</KibanaContextProvider> | ||
</startServices.i18n.Context> | ||
); | ||
} | ||
); | ||
|
||
export const AppRoutes = memo(() => { | ||
const { agents } = useConfig(); | ||
|
||
return ( | ||
<Switch> | ||
<Route path={PAGE_ROUTING_PATHS.integrations}> | ||
<DefaultLayout section="epm"> | ||
<EPMApp /> | ||
</DefaultLayout> | ||
</Route> | ||
<Route path={PAGE_ROUTING_PATHS.policies}> | ||
<DefaultLayout section="agent_policy"> | ||
<AgentPolicyApp /> | ||
</DefaultLayout> | ||
</Route> | ||
<Route path={PAGE_ROUTING_PATHS.data_streams}> | ||
<DefaultLayout section="data_stream"> | ||
<DataStreamApp /> | ||
</DefaultLayout> | ||
</Route> | ||
<ProtectedRoute path={PAGE_ROUTING_PATHS.fleet} isAllowed={agents.enabled}> | ||
<DefaultLayout section="fleet"> | ||
<FleetApp /> | ||
</DefaultLayout> | ||
</ProtectedRoute> | ||
<Route exact path={PAGE_ROUTING_PATHS.overview}> | ||
<DefaultLayout section="overview"> | ||
<IngestManagerOverview /> | ||
</DefaultLayout> | ||
</Route> | ||
<Redirect to="/" /> | ||
</Switch> | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note the subtle change from using
HashRouter
to usingRouter
along with History'screateHashHistory
. This is so that it can support testing.