mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
This commit is contained in:
parent
c82ee2ada2
commit
631fd9da50
10 changed files with 126 additions and 10 deletions
|
@ -51,5 +51,5 @@ export class LicenseService {
|
|||
}
|
||||
|
||||
export const isAtLeast = (license: ILicense | null, level: LicenseType): boolean => {
|
||||
return license !== null && license.isAvailable && license.isActive && license.hasAtLeast(level);
|
||||
return !!license && license.isAvailable && license.isActive && license.hasAtLeast(level);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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, { FC, memo, useEffect } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { licenseService } from '../../hooks/use_license';
|
||||
import { AppAction } from '../../store/actions';
|
||||
import { ILicense } from '../../../../../licensing/common/types';
|
||||
|
||||
export const CurrentLicense: FC = memo(({ children }) => {
|
||||
const dispatch = useDispatch<Dispatch<AppAction>>();
|
||||
useEffect(() => {
|
||||
const subscription = licenseService
|
||||
.getLicenseInformation$()
|
||||
?.subscribe((licenseInformation: ILicense) => {
|
||||
dispatch({
|
||||
type: 'licenseChanged',
|
||||
payload: licenseInformation,
|
||||
});
|
||||
});
|
||||
return () => subscription?.unsubscribe();
|
||||
}, [dispatch]);
|
||||
return <>{children}</>;
|
||||
});
|
||||
|
||||
CurrentLicense.displayName = 'CurrentLicense';
|
|
@ -4,6 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ILicense } from '../../../../../../../licensing/common/types';
|
||||
import { GetAgentStatusResponse } from '../../../../../../../fleet/common/types/rest_spec';
|
||||
import { PolicyData, UIPolicyConfig } from '../../../../../../common/endpoint/types';
|
||||
import { ServerApiError } from '../../../../../common/types';
|
||||
|
@ -62,6 +63,11 @@ interface UserClickedPolicyDetailsSaveButton {
|
|||
type: 'userClickedPolicyDetailsSaveButton';
|
||||
}
|
||||
|
||||
interface LicenseChanged {
|
||||
type: 'licenseChanged';
|
||||
payload: ILicense;
|
||||
}
|
||||
|
||||
export type PolicyDetailsAction =
|
||||
| ServerReturnedPolicyDetailsData
|
||||
| UserClickedPolicyDetailsSaveButton
|
||||
|
@ -70,4 +76,5 @@ export type PolicyDetailsAction =
|
|||
| ServerReturnedUpdatedPolicyDetailsData
|
||||
| ServerFailedToReturnPolicyDetailsData
|
||||
| UserChangedPolicyConfig
|
||||
| UserChangedAntivirusRegistration;
|
||||
| UserChangedAntivirusRegistration
|
||||
| LicenseChanged;
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
} from '../../../../../common/mock/endpoint';
|
||||
import { HttpFetchOptions } from 'kibana/public';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { licenseMock } from '../../../../../../../licensing/common/licensing.mock';
|
||||
|
||||
describe('policy details: ', () => {
|
||||
let store: Store;
|
||||
|
@ -151,6 +152,49 @@ describe('policy details: ', () => {
|
|||
expect(config!.linux.events.file).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the policy config has paid features enabled', () => {
|
||||
const CustomMessage = 'Some Popup message change';
|
||||
const Basic = licenseMock.createLicense({ license: { type: 'basic', mode: 'basic' } });
|
||||
const Platinum = licenseMock.createLicense({
|
||||
license: { type: 'platinum', mode: 'platinum' },
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
const config = policyConfig(getState());
|
||||
if (!config) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
// have a paid-policy field existing in the store from a previous time
|
||||
const newPayload1 = cloneDeep(config);
|
||||
newPayload1.windows.popup.malware.message = CustomMessage;
|
||||
dispatch({
|
||||
type: 'userChangedPolicyConfig',
|
||||
payload: { policyConfig: newPayload1 },
|
||||
});
|
||||
});
|
||||
|
||||
it('preserves paid fields when license level allows', () => {
|
||||
dispatch({
|
||||
type: 'licenseChanged',
|
||||
payload: Platinum,
|
||||
});
|
||||
const config = policyConfig(getState());
|
||||
|
||||
expect(config.windows.popup.malware.message).toEqual(CustomMessage);
|
||||
});
|
||||
|
||||
it('reverts paid fields to default when license level does not allow', () => {
|
||||
dispatch({
|
||||
type: 'licenseChanged',
|
||||
payload: Basic,
|
||||
});
|
||||
const config = policyConfig(getState());
|
||||
|
||||
expect(config.windows.popup.malware.message).not.toEqual(CustomMessage);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when saving policy data', () => {
|
||||
|
|
|
@ -26,7 +26,6 @@ export const policyDetailsMiddlewareFactory: ImmutableMiddlewareFactory<PolicyDe
|
|||
coreStart
|
||||
) => {
|
||||
const http = coreStart.http;
|
||||
|
||||
return ({ getState, dispatch }) => (next) => async (action) => {
|
||||
next(action);
|
||||
const state = getState();
|
||||
|
|
|
@ -45,6 +45,7 @@ export const initialPolicyDetailsState: () => Immutable<PolicyDetailsState> = ()
|
|||
total: 0,
|
||||
other: 0,
|
||||
},
|
||||
license: undefined,
|
||||
});
|
||||
|
||||
export const policyDetailsReducer: ImmutableReducer<PolicyDetailsState, AppAction> = (
|
||||
|
@ -93,6 +94,13 @@ export const policyDetailsReducer: ImmutableReducer<PolicyDetailsState, AppActio
|
|||
};
|
||||
}
|
||||
|
||||
if (action.type === 'licenseChanged') {
|
||||
return {
|
||||
...state,
|
||||
license: action.payload,
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === 'userChangedUrl') {
|
||||
const newState: Immutable<PolicyDetailsState> = {
|
||||
...state,
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
import { createSelector } from 'reselect';
|
||||
import { matchPath } from 'react-router-dom';
|
||||
import { ILicense } from '../../../../../../../licensing/common/types';
|
||||
import { unsetPolicyFeaturesAboveLicenseLevel } from '../../../../../../common/license/policy_config';
|
||||
import { PolicyDetailsState } from '../../types';
|
||||
import {
|
||||
Immutable,
|
||||
|
@ -20,6 +22,24 @@ import { ManagementRoutePolicyDetailsParams } from '../../../../types';
|
|||
|
||||
/** Returns the policy details */
|
||||
export const policyDetails = (state: Immutable<PolicyDetailsState>) => state.policyItem;
|
||||
/** Returns current active license */
|
||||
export const licenseState = (state: Immutable<PolicyDetailsState>) => state.license;
|
||||
|
||||
export const licensedPolicy: (
|
||||
state: Immutable<PolicyDetailsState>
|
||||
) => Immutable<PolicyData> | undefined = createSelector(
|
||||
policyDetails,
|
||||
licenseState,
|
||||
(policyData, license) => {
|
||||
if (policyData) {
|
||||
unsetPolicyFeaturesAboveLicenseLevel(
|
||||
policyData?.inputs[0]?.config.policy.value,
|
||||
license as ILicense
|
||||
);
|
||||
}
|
||||
return policyData;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Given a Policy Data (package policy) object, return back a new object with only the field
|
||||
|
@ -75,7 +95,7 @@ export const getPolicyDataForUpdate = (
|
|||
*/
|
||||
export const policyDetailsForUpdate: (
|
||||
state: Immutable<PolicyDetailsState>
|
||||
) => Immutable<NewPolicyData> | undefined = createSelector(policyDetails, (policy) => {
|
||||
) => Immutable<NewPolicyData> | undefined = createSelector(licensedPolicy, (policy) => {
|
||||
if (policy) {
|
||||
return getPolicyDataForUpdate(policy);
|
||||
}
|
||||
|
@ -111,7 +131,7 @@ const defaultFullPolicy: Immutable<PolicyConfig> = policyConfigFactory();
|
|||
* Note: this will return a default full policy if the `policyItem` is `undefined`
|
||||
*/
|
||||
export const fullPolicy: (s: Immutable<PolicyDetailsState>) => PolicyConfig = createSelector(
|
||||
policyDetails,
|
||||
licensedPolicy,
|
||||
(policyData) => {
|
||||
return policyData?.inputs[0]?.config?.policy?.value ?? defaultFullPolicy;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ILicense } from '../../../../../licensing/common/types';
|
||||
import {
|
||||
AppLocation,
|
||||
Immutable,
|
||||
|
@ -66,6 +67,8 @@ export interface PolicyDetailsState {
|
|||
success: boolean;
|
||||
error?: ServerApiError;
|
||||
};
|
||||
/** current license */
|
||||
license?: ILicense;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,7 @@ import React, { ComponentType, memo } from 'react';
|
|||
import { CoreStart } from 'kibana/public';
|
||||
import { combineReducers, createStore, compose, applyMiddleware } from 'redux';
|
||||
import { Provider as ReduxStoreProvider } from 'react-redux';
|
||||
import { CurrentLicense } from '../../../../../common/components/current_license';
|
||||
import { StartPlugins } from '../../../../../types';
|
||||
import { managementReducer } from '../../../../store/reducer';
|
||||
import { managementMiddlewareFactory } from '../../../../store/middleware';
|
||||
|
@ -57,7 +58,9 @@ export const withSecurityContext = <P extends {}>({
|
|||
|
||||
return (
|
||||
<ReduxStoreProvider store={store}>
|
||||
<WrappedComponent {...props} />
|
||||
<CurrentLicense>
|
||||
<WrappedComponent {...props} />
|
||||
</CurrentLicense>
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -8,13 +8,16 @@ import React from 'react';
|
|||
import { Route, Switch } from 'react-router-dom';
|
||||
import { ManagementContainer } from './pages';
|
||||
import { NotFoundPage } from '../app/404';
|
||||
import { CurrentLicense } from '../common/components/current_license';
|
||||
|
||||
/**
|
||||
* Returns the React Router Routes for the management area
|
||||
*/
|
||||
export const ManagementRoutes = () => (
|
||||
<Switch>
|
||||
<Route path="/" component={ManagementContainer} />
|
||||
<Route render={() => <NotFoundPage />} />
|
||||
</Switch>
|
||||
<CurrentLicense>
|
||||
<Switch>
|
||||
<Route path="/" component={ManagementContainer} />
|
||||
<Route render={() => <NotFoundPage />} />
|
||||
</Switch>
|
||||
</CurrentLicense>
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue