Skip to content

Commit

Permalink
Merge branch 'master' into alerting/client-types
Browse files Browse the repository at this point in the history
* master:
  Bump year in NOTICE.txt
  Add kibanamachine support to Github PR comments (elastic#53852)
  Add tests to ensure AAD isn't broken after performing a change on an alert / action (elastic#53333)
  Skip failing test suite
  [Vega] Sample [Flights] Airport Connections (Hover Over Airport) visualization not working (elastic#53799)
  Do not remount applications between page navigations (elastic#53851)
  [Canvas] Refactor Canvas to no longer use componentWillReceiveProps (elastic#52129)
  [Canvas] Migrate usage collector to NP plugin (elastic#53303)
  • Loading branch information
gmmorris committed Jan 2, 2020
2 parents be3b3a2 + 650fcda commit fa3e74f
Show file tree
Hide file tree
Showing 54 changed files with 555 additions and 116 deletions.
2 changes: 1 addition & 1 deletion NOTICE.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Kibana source code with Kibana X-Pack source code
Copyright 2012-2019 Elasticsearch B.V.
Copyright 2012-2020 Elasticsearch B.V.

---
Pretty handling of logarithmic axes.
Expand Down
84 changes: 70 additions & 14 deletions src/core/public/application/integration_tests/router.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

import React from 'react';
import { createMemoryHistory, History } from 'history';
import { createMemoryHistory, History, createHashHistory } from 'history';

import { AppRouter, AppNotFound } from '../ui';
import { EitherApp, MockedMounterMap, MockedMounterTuple } from '../test_types';
Expand All @@ -27,7 +27,15 @@ import { createRenderer, createAppMounter, createLegacyAppMounter } from './util
describe('AppContainer', () => {
let mounters: MockedMounterMap<EitherApp>;
let history: History;
let navigate: ReturnType<typeof createRenderer>;
let update: ReturnType<typeof createRenderer>;

const navigate = (path: string) => {
history.push(path);
return update();
};

const mockMountersToMounters = () =>
new Map([...mounters].map(([appId, { mounter }]) => [appId, mounter]));

beforeEach(() => {
mounters = new Map([
Expand All @@ -38,26 +46,26 @@ describe('AppContainer', () => {
createAppMounter('app3', '<div>App 3</div>', '/custom/path'),
] as Array<MockedMounterTuple<EitherApp>>);
history = createMemoryHistory();
navigate = createRenderer(<AppRouter history={history} mounters={mounters} />, history.push);
update = createRenderer(<AppRouter history={history} mounters={mockMountersToMounters()} />);
});

it('calls mount handler and returned unmount function when navigating between apps', async () => {
const dom1 = await navigate('/app/app1');
const app1 = mounters.get('app1')!;

expect(app1.mount).toHaveBeenCalled();
expect(app1.mounter.mount).toHaveBeenCalled();
expect(dom1?.html()).toMatchInlineSnapshot(`
"<div><div>
basename: /app/app1
html: <span>App 1</span>
</div></div>"
`);

const app1Unmount = await app1.mount.mock.results[0].value;
const app1Unmount = await app1.mounter.mount.mock.results[0].value;
const dom2 = await navigate('/app/app2');

expect(app1Unmount).toHaveBeenCalled();
expect(mounters.get('app2')!.mount).toHaveBeenCalled();
expect(mounters.get('app2')!.mounter.mount).toHaveBeenCalled();
expect(dom2?.html()).toMatchInlineSnapshot(`
"<div><div>
basename: /app/app2
Expand All @@ -70,29 +78,77 @@ describe('AppContainer', () => {
mounters.set(...createAppMounter('spaces', '<div>Custom Space</div>', '/spaces/fake-login'));
mounters.set(...createAppMounter('login', '<div>Login Page</div>', '/fake-login'));
history = createMemoryHistory();
navigate = createRenderer(<AppRouter history={history} mounters={mounters} />, history.push);
update = createRenderer(<AppRouter history={history} mounters={mockMountersToMounters()} />);

await navigate('/fake-login');

expect(mounters.get('spaces')!.mount).not.toHaveBeenCalled();
expect(mounters.get('login')!.mount).toHaveBeenCalled();
expect(mounters.get('spaces')!.mounter.mount).not.toHaveBeenCalled();
expect(mounters.get('login')!.mounter.mount).toHaveBeenCalled();
});

it('should not mount when partial route path has higher specificity', async () => {
mounters.set(...createAppMounter('login', '<div>Login Page</div>', '/fake-login'));
mounters.set(...createAppMounter('spaces', '<div>Custom Space</div>', '/spaces/fake-login'));
history = createMemoryHistory();
navigate = createRenderer(<AppRouter history={history} mounters={mounters} />, history.push);
update = createRenderer(<AppRouter history={history} mounters={mockMountersToMounters()} />);

await navigate('/spaces/fake-login');

expect(mounters.get('spaces')!.mount).toHaveBeenCalled();
expect(mounters.get('login')!.mount).not.toHaveBeenCalled();
expect(mounters.get('spaces')!.mounter.mount).toHaveBeenCalled();
expect(mounters.get('login')!.mounter.mount).not.toHaveBeenCalled();
});

it('should not remount when changing pages within app', async () => {
const { mounter, unmount } = mounters.get('app1')!;
await navigate('/app/app1/page1');
expect(mounter.mount).toHaveBeenCalledTimes(1);

// Navigating to page within app does not trigger re-render
await navigate('/app/app1/page2');
expect(mounter.mount).toHaveBeenCalledTimes(1);
expect(unmount).not.toHaveBeenCalled();
});

it('should not remount when going back within app', async () => {
const { mounter, unmount } = mounters.get('app1')!;
await navigate('/app/app1/page1');
expect(mounter.mount).toHaveBeenCalledTimes(1);

// Hitting back button within app does not trigger re-render
await navigate('/app/app1/page2');
history.goBack();
await update();
expect(mounter.mount).toHaveBeenCalledTimes(1);
expect(unmount).not.toHaveBeenCalled();
});

it('should not remount when when changing pages within app using hash history', async () => {
history = createHashHistory();
update = createRenderer(<AppRouter history={history} mounters={mockMountersToMounters()} />);

const { mounter, unmount } = mounters.get('app1')!;
await navigate('/app/app1/page1');
expect(mounter.mount).toHaveBeenCalledTimes(1);

// Changing hash history does not trigger re-render
await navigate('/app/app1/page2');
expect(mounter.mount).toHaveBeenCalledTimes(1);
expect(unmount).not.toHaveBeenCalled();
});

it('should unmount when changing between apps', async () => {
const { mounter, unmount } = mounters.get('app1')!;
await navigate('/app/app1/page1');
expect(mounter.mount).toHaveBeenCalledTimes(1);

// Navigating to other app triggers unmount
await navigate('/app/app2/page1');
expect(unmount).toHaveBeenCalledTimes(1);
});

it('calls legacy mount handler', async () => {
await navigate('/app/legacyApp1');
expect(mounters.get('legacyApp1')!.mount.mock.calls[0]).toMatchInlineSnapshot(`
expect(mounters.get('legacyApp1')!.mounter.mount.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Object {
"appBasePath": "/app/legacyApp1",
Expand All @@ -104,7 +160,7 @@ describe('AppContainer', () => {

it('handles legacy apps with subapps', async () => {
await navigate('/app/baseApp');
expect(mounters.get('baseApp:legacyApp2')!.mount.mock.calls[0]).toMatchInlineSnapshot(`
expect(mounters.get('baseApp:legacyApp2')!.mounter.mount.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Object {
"appBasePath": "/app/baseApp",
Expand Down
56 changes: 30 additions & 26 deletions src/core/public/application/integration_tests/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,13 @@ import { App, LegacyApp, AppMountParameters } from '../types';
import { MockedMounter, MockedMounterTuple } from '../test_types';

type Dom = ReturnType<typeof mount> | null;
type Renderer = (item: string) => Dom | Promise<Dom>;
type Renderer = () => Dom | Promise<Dom>;

export const createRenderer = (
element: ReactElement | null,
callback?: (item: string) => void | Promise<void>
): Renderer => {
export const createRenderer = (element: ReactElement | null): Renderer => {
const dom: Dom = element && mount(<I18nProvider>{element}</I18nProvider>);

return item =>
return () =>
new Promise(async resolve => {
if (callback) {
await callback(item);
}
if (dom) {
dom.update();
}
Expand All @@ -50,29 +44,39 @@ export const createAppMounter = (
appId: string,
html: string,
appRoute = `/app/${appId}`
): MockedMounterTuple<App> => [
appId,
{
appRoute,
appBasePath: appRoute,
mount: jest.fn(async ({ appBasePath: basename, element }: AppMountParameters) => {
Object.assign(element, {
innerHTML: `<div>\nbasename: ${basename}\nhtml: ${html}\n</div>`,
});
return jest.fn(() => Object.assign(element, { innerHTML: '' }));
}),
},
];
): MockedMounterTuple<App> => {
const unmount = jest.fn();
return [
appId,
{
mounter: {
appRoute,
appBasePath: appRoute,
mount: jest.fn(async ({ appBasePath: basename, element }: AppMountParameters) => {
Object.assign(element, {
innerHTML: `<div>\nbasename: ${basename}\nhtml: ${html}\n</div>`,
});
unmount.mockImplementation(() => Object.assign(element, { innerHTML: '' }));
return unmount;
}),
},
unmount,
},
];
};

export const createLegacyAppMounter = (
appId: string,
legacyMount: MockedMounter<LegacyApp>['mount']
): MockedMounterTuple<LegacyApp> => [
appId,
{
appRoute: `/app/${appId.split(':')[0]}`,
appBasePath: `/app/${appId.split(':')[0]}`,
unmountBeforeMounting: true,
mount: legacyMount,
mounter: {
appRoute: `/app/${appId.split(':')[0]}`,
appBasePath: `/app/${appId.split(':')[0]}`,
unmountBeforeMounting: true,
mount: legacyMount,
},
unmount: jest.fn(),
},
];
14 changes: 11 additions & 3 deletions src/core/public/application/test_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,27 @@
* under the License.
*/

import { App, LegacyApp, Mounter } from './types';
import { App, LegacyApp, Mounter, AppUnmount } from './types';
import { ApplicationService } from './application_service';

/** @internal */
export type ApplicationServiceContract = PublicMethodsOf<ApplicationService>;
/** @internal */
export type EitherApp = App | LegacyApp;
/** @internal */
export type MockedUnmount = jest.Mocked<AppUnmount>;
/** @internal */
export type MockedMounter<T extends EitherApp> = jest.Mocked<Mounter<jest.Mocked<T>>>;
/** @internal */
export type MockedMounterTuple<T extends EitherApp> = [string, MockedMounter<T>];
export type MockedMounterTuple<T extends EitherApp> = [
string,
{ mounter: MockedMounter<T>; unmount: MockedUnmount }
];
/** @internal */
export type MockedMounterMap<T extends EitherApp> = Map<string, MockedMounter<T>>;
export type MockedMounterMap<T extends EitherApp> = Map<
string,
{ mounter: MockedMounter<T>; unmount: MockedUnmount }
>;
/** @internal */
export type MockLifecycle<
T extends keyof ApplicationService,
Expand Down
2 changes: 1 addition & 1 deletion src/core/public/application/ui/app_container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const AppContainer: FunctionComponent<Props> = ({ mounter, appId }: Props

mount();
return unmount;
});
}, [mounter]);

return (
<Fragment>
Expand Down
2 changes: 1 addition & 1 deletion src/core/server/rendering/views/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export const Styles: FunctionComponent<Props> = ({ darkMode }) => {
background-repeat: no-repeat;
background-size: contain;
/* SVG optimized according to http://codepen.io/tigt/post/optimizing-svgs-in-data-uris */
background-image: url'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMCIgaGVpZ2h0PSIzOSIgdmlld0JveD0iMCAwIDMwIDM5Ij4gIDxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+ICAgIDxwb2x5Z29uIGZpbGw9IiNGMDRFOTgiIHBvaW50cz0iMCAwIDAgMzQuNTQ3IDI5LjkyMiAuMDIiLz4gICAgPHBhdGggZmlsbD0iIzM0Mzc0MSIgZD0iTTAsMTQuNCBMMCwzNC41NDY4IEwxNC4yODcyLDE4LjA2MTIgQzEwLjA0MTYsMTUuNzM4IDUuMTgwNCwxNC40IDAsMTQuNCIvPiAgICA8cGF0aCBmaWxsPSIjMDBCRkIzIiBkPSJNMTcuMzc0MiwxOS45OTY4IEwyLjcyMSwzNi45MDQ4IEwxLjQzMzQsMzguMzg5MiBMMjkuMjYzOCwzOC4zODkyIEMyNy43NjE0LDMwLjgzODggMjMuNDA0MiwyNC4zMjY0IDE3LjM3NDIsMTkuOTk2OCIvPiAgPC9nPjwvc3ZnPg==');
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMCIgaGVpZ2h0PSIzOSIgdmlld0JveD0iMCAwIDMwIDM5Ij4gIDxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+ICAgIDxwb2x5Z29uIGZpbGw9IiNGMDRFOTgiIHBvaW50cz0iMCAwIDAgMzQuNTQ3IDI5LjkyMiAuMDIiLz4gICAgPHBhdGggZmlsbD0iIzM0Mzc0MSIgZD0iTTAsMTQuNCBMMCwzNC41NDY4IEwxNC4yODcyLDE4LjA2MTIgQzEwLjA0MTYsMTUuNzM4IDUuMTgwNCwxNC40IDAsMTQuNCIvPiAgICA8cGF0aCBmaWxsPSIjMDBCRkIzIiBkPSJNMTcuMzc0MiwxOS45OTY4IEwyLjcyMSwzNi45MDQ4IEwxLjQzMzQsMzguMzg5MiBMMjkuMjYzOCwzOC4zODkyIEMyNy43NjE0LDMwLjgzODggMjMuNDA0MiwyNC4zMjY0IDE3LjM3NDIsMTkuOTk2OCIvPiAgPC9nPjwvc3ZnPg==');
}
.kibanaWelcomeTitle {
Expand Down
9 changes: 8 additions & 1 deletion src/legacy/core_plugins/tile_map/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ const tileMapPluginInitializer: LegacyPluginInitializer = ({ Plugin }: LegacyPlu
uiExports: {
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
hacks: [resolve(__dirname, 'public/legacy')],
injectDefaultVars: server => ({}),
injectDefaultVars: server => {
const serverConfig = server.config();
const mapConfig: Record<string, any> = serverConfig.get('map');

return {
emsTileLayerId: mapConfig.emsTileLayerId,
};
},
},
config(Joi: any) {
return Joi.object({
Expand Down
12 changes: 9 additions & 3 deletions src/legacy/core_plugins/vis_type_vega/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,15 @@ const vegaPluginInitializer: LegacyPluginInitializer = ({ Plugin }: LegacyPlugin
uiExports: {
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
hacks: [resolve(__dirname, 'public/legacy')],
injectDefaultVars: server => ({
enableExternalUrls: server.config().get('vega.enableExternalUrls'),
}),
injectDefaultVars: server => {
const serverConfig = server.config();
const mapConfig: Record<string, any> = serverConfig.get('map');

return {
emsTileLayerId: mapConfig.emsTileLayerId,
enableExternalUrls: serverConfig.get('vega.enableExternalUrls'),
};
},
},
init: (server: Legacy.Server) => ({}),
config(Joi: any) {
Expand Down
3 changes: 2 additions & 1 deletion test/functional/apps/home/_newsfeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export default function({ getService, getPageObjects }: FtrProviderContext) {
const globalNav = getService('globalNav');
const PageObjects = getPageObjects(['common', 'newsfeed']);

describe('Newsfeed', () => {
// Failing: https://github.com/elastic/kibana/issues/53860
describe.skip('Newsfeed', () => {
before(async () => {
await PageObjects.newsfeed.resetPage();
});
Expand Down
4 changes: 2 additions & 2 deletions vars/githubPr.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def withDefaultPrComments(closure) {
def message = getNextCommentMessage(info)
postComment(message)

if (lastComment) {
if (lastComment && lastComment.user.login == 'kibanamachine') {
deleteComment(lastComment.id)
}
}
Expand All @@ -49,7 +49,7 @@ def isPr() {
def getLatestBuildComment() {
return getComments()
.reverse()
.find { it.user.login == 'elasticmachine' && it.body =~ /<!--PIPELINE/ }
.find { (it.user.login == 'elasticmachine' || it.user.login == 'kibanamachine') && it.body =~ /<!--PIPELINE/ }
}

def getBuildInfoFromComment(commentText) {
Expand Down
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/alerting/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class Plugin {
attributesToEncrypt: new Set(['apiKey']),
attributesToExcludeFromAAD: new Set([
'scheduledTaskId',
'muted',
'muteAll',
'mutedInstanceIds',
'updatedBy',
]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,20 @@ export const DatetimeInput = compose<ComponentProps, Props>(
moment ? moment.format('YYYY-MM-DD HH:mm:ss') : ''
),
lifecycle<Props & ComponentProps, {}>({
// TODO: Refactor to no longer use componentWillReceiveProps since it is being deprecated
componentWillReceiveProps({ moment, setStrValue, setValid }) {
if (!moment) return;
componentDidUpdate(prevProps) {
const prevMoment = prevProps.moment;

if (this.props.moment && this.props.moment.isSame(moment)) {
// If we don't have a current moment, do nothing
if (!this.props.moment) return;

// If we previously had a moment and it's the same as the current moment, do nothing
if (prevMoment && prevMoment.isSame(this.props.moment)) {
return;
}
setStrValue(moment.format('YYYY-MM-DD HH:mm:ss'));
setValid(true);

// Set the string value of the current moment and mark as valid
this.props.setStrValue(this.props.moment.format('YYYY-MM-DD HH:mm:ss'));
this.props.setValid(true);
},
})
)(Component);
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ export class TimePicker extends Component<Props, State> {
isDirty: false,
};

// TODO: Refactor to no longer use componentWillReceiveProps since it is being deprecated
UNSAFE_componentWillReceiveProps({ from, to }: Props) {
if (from !== this.props.from || to !== this.props.to) {
componentDidUpdate(prevProps: Props) {
const { to, from } = this.props;

if (prevProps.from !== from || prevProps.to !== to) {
this.setState({
range: { from, to },
isDirty: false,
Expand Down
Loading

0 comments on commit fa3e74f

Please sign in to comment.