Skip to content

Commit c14047c

Browse files
committed
Fix react hooks ordering bug with license status updates and fix test (wait for first license object before rendering)
1 parent 5994f61 commit c14047c

File tree

7 files changed

+40
-30
lines changed

7 files changed

+40
-30
lines changed

x-pack/plugins/searchprofiler/public/application/boot.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
import { render, unmountComponentAtNode } from 'react-dom';
77
import { HttpStart as Http, ToastsSetup } from 'kibana/public';
88
import React from 'react';
9+
910
import { LicenseStatus } from '../../common/types';
1011
import { App } from '.';
1112

1213
export interface Dependencies {
1314
el: HTMLElement;
1415
http: Http;
15-
getLicenseStatus: () => LicenseStatus;
1616
I18nContext: any;
1717
notifications: ToastsSetup;
18+
initialLicenseStatus: LicenseStatus;
1819
}
1920

2021
export type AppDependencies = Omit<Dependencies, 'el'>;

x-pack/plugins/searchprofiler/public/application/components/license_warning_notice.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const LicenseWarningNotice = () => {
3636
title={i18n.translate('xpack.searchProfiler.licenseErrorMessageTitle', {
3737
defaultMessage: 'License error',
3838
})}
39-
color="warning"
39+
color="danger"
4040
iconType="alert"
4141
style={{ padding: '16px' }}
4242
>

x-pack/plugins/searchprofiler/public/application/contexts/app_context.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,17 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import React, { useContext, createContext } from 'react';
7+
import React, { useContext, createContext, useCallback } from 'react';
8+
89
import { HttpSetup, ToastsSetup } from 'kibana/public';
910
import { LicenseStatus } from '../../../common/types';
1011

12+
export interface ContextArgs {
13+
http: HttpSetup;
14+
notifications: ToastsSetup;
15+
initialLicenseStatus: LicenseStatus;
16+
}
17+
1118
export interface ContextValue {
1219
http: HttpSetup;
1320
notifications: ToastsSetup;
@@ -18,12 +25,24 @@ const AppContext = createContext<ContextValue>(null as any);
1825

1926
export const AppContextProvider = ({
2027
children,
21-
value,
28+
args: { http, notifications, initialLicenseStatus },
2229
}: {
2330
children: React.ReactNode;
24-
value: ContextValue;
31+
args: ContextArgs;
2532
}) => {
26-
return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
33+
const getLicenseStatus = useCallback(() => initialLicenseStatus, [initialLicenseStatus]);
34+
35+
return (
36+
<AppContext.Provider
37+
value={{
38+
http,
39+
notifications,
40+
getLicenseStatus,
41+
}}
42+
>
43+
{children}
44+
</AppContext.Provider>
45+
);
2746
};
2847

2948
export const useAppContext = () => {

x-pack/plugins/searchprofiler/public/application/editor/editor.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,13 @@ export const Editor = memo(({ licenseEnabled, initialValue, onEditorReady }: Pro
3737

3838
const [textArea, setTextArea] = useState<HTMLTextAreaElement | null>(null);
3939

40-
if (licenseEnabled) {
41-
useUIAceKeyboardMode(textArea);
42-
}
40+
useUIAceKeyboardMode(textArea);
4341

4442
useEffect(() => {
4543
const divEl = containerRef.current;
4644
editorInstanceRef.current = initializeEditor({ el: divEl, licenseEnabled });
4745
editorInstanceRef.current.setValue(initialValue, 1);
48-
setTextArea(containerRef.current!.querySelector('textarea'));
46+
setTextArea(licenseEnabled ? containerRef.current!.querySelector('textarea') : null);
4947

5048
onEditorReady(createEditorShim(editorInstanceRef.current));
5149
}, [initialValue, onEditorReady, licenseEnabled]);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import { ProfileContextProvider } from './contexts/profiler_context';
1010

1111
import { AppDependencies } from './boot';
1212

13-
export function App({ I18nContext, getLicenseStatus, notifications, http }: AppDependencies) {
13+
export function App({ I18nContext, initialLicenseStatus, notifications, http }: AppDependencies) {
1414
return (
1515
<I18nContext>
16-
<AppContextProvider value={{ getLicenseStatus, notifications, http }}>
16+
<AppContextProvider args={{ initialLicenseStatus, notifications, http }}>
1717
<ProfileContextProvider>
1818
<Main />
1919
</ProfileContextProvider>

x-pack/plugins/searchprofiler/public/plugin.ts

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,16 @@
66

77
import { i18n } from '@kbn/i18n';
88
import { Plugin, CoreStart, CoreSetup, PluginInitializerContext } from 'kibana/public';
9+
import { first } from 'rxjs/operators';
910

1011
import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public';
1112
import { LICENSE_CHECK_STATE } from '../../licensing/public';
1213

1314
import { PLUGIN } from '../common/constants';
1415
import { AppPublicPluginDependencies } from './types';
15-
import { LicenseStatus } from '../common/types';
1616

1717
export class SearchProfilerUIPlugin implements Plugin<void, void, AppPublicPluginDependencies> {
18-
private licenseStatus: LicenseStatus;
19-
20-
constructor(ctx: PluginInitializerContext) {
21-
this.licenseStatus = { valid: false };
22-
}
18+
constructor(ctx: PluginInitializerContext) {}
2319

2420
async setup(
2521
{ http, getStartServices }: CoreSetup,
@@ -50,25 +46,21 @@ export class SearchProfilerUIPlugin implements Plugin<void, void, AppPublicPlugi
5046
const [coreStart] = await getStartServices();
5147
const { notifications, i18n: i18nDep } = coreStart;
5248
const { boot } = await import('./application/boot');
49+
50+
const license = await licensing.license$.pipe(first()).toPromise();
51+
const { state, message } = license.check(PLUGIN.id, PLUGIN.minimumLicenseType);
52+
const initialLicenseStatus =
53+
state === LICENSE_CHECK_STATE.Valid ? { valid: true } : { valid: false, message };
54+
5355
return boot({
5456
http,
55-
getLicenseStatus: () => this.licenseStatus,
57+
initialLicenseStatus,
5658
el: params.element,
5759
I18nContext: i18nDep.Context,
5860
notifications: notifications.toasts,
5961
});
6062
},
6163
});
62-
63-
licensing.license$.subscribe(license => {
64-
const { state, message } = license.check(PLUGIN.id, PLUGIN.minimumLicenseType);
65-
const isAvailable = state === LICENSE_CHECK_STATE.Valid;
66-
if (isAvailable) {
67-
this.licenseStatus = { valid: true };
68-
} else {
69-
this.licenseStatus = { valid: false, message };
70-
}
71-
});
7264
}
7365

7466
async start(core: CoreStart, plugins: any) {}

x-pack/test/functional/apps/dev_tools/searchprofiler_editor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) {
5151
await aceEditor.setValue(editorTestSubjectSelector, input);
5252

5353
await retry.waitFor(
54-
`parser errors to match expection: HAS ${expectation ? 'ERRORS' : 'NO ERRORS'}`,
54+
`parser errors to match expectation: HAS ${expectation ? 'ERRORS' : 'NO ERRORS'}`,
5555
async () => {
5656
const actual = await aceEditor.hasParseErrors(editorTestSubjectSelector);
5757
return expectation === actual;

0 commit comments

Comments
 (0)