Skip to content

Commit

Permalink
Merge branch '7.x' into backport/7.x/pr-86902
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Jan 4, 2021
2 parents 9ab9d1d + a8dce50 commit 2a6708d
Show file tree
Hide file tree
Showing 24 changed files with 344 additions and 151 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
"@hapi/good-squeeze": "6.0.0",
"@hapi/h2o2": "^9.0.2",
"@hapi/hapi": "^20.0.3",
"@hapi/hoek": "^9.1.0",
"@hapi/hoek": "^9.1.1",
"@hapi/inert": "^6.0.3",
"@hapi/podium": "^4.1.1",
"@hapi/statehood": "^7.0.3",
Expand Down
21 changes: 1 addition & 20 deletions src/core/server/http/cookie_session_storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

import { Request, Server } from '@hapi/hapi';
import hapiAuthCookie from '@hapi/cookie';
// @ts-expect-error no TS definitions
import Statehood from '@hapi/statehood';

import { KibanaRequest, ensureRawRequest } from './router';
import { SessionStorageFactory, SessionStorage } from './session_storage';
Expand Down Expand Up @@ -148,7 +146,7 @@ export async function createCookieSessionStorageFactory<T>(
path: basePath === undefined ? '/' : basePath,
clearInvalid: false,
isHttpOnly: true,
isSameSite: cookieOptions.sameSite === 'None' ? false : cookieOptions.sameSite ?? false,
isSameSite: cookieOptions.sameSite ?? false,
},
validateFunc: async (req: Request, session: T | T[]) => {
const result = cookieOptions.validate(session);
Expand All @@ -159,23 +157,6 @@ export async function createCookieSessionStorageFactory<T>(
},
});

// A hack to support SameSite: 'None'.
// Remove it after update Hapi to v19 that supports SameSite: 'None' out of the box.
if (cookieOptions.sameSite === 'None') {
log.debug('Patching Statehood.prepareValue');
const originalPrepareValue = Statehood.prepareValue;
Statehood.prepareValue = function kibanaStatehoodPrepareValueWrapper(
name: string,
value: unknown,
options: any
) {
if (name === cookieOptions.name) {
options.isSameSite = cookieOptions.sameSite;
}
return originalPrepareValue(name, value, options);
};
}

return {
asScoped(request: KibanaRequest) {
return new ScopedCookieSessionStorage<T>(log, server, ensureRawRequest(request));
Expand Down
28 changes: 10 additions & 18 deletions src/core/server/http/http_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { Server, ServerRoute } from '@hapi/hapi';
import { Server } from '@hapi/hapi';
import HapiStaticFiles from '@hapi/inert';
import url from 'url';
import uuid from 'uuid';
Expand Down Expand Up @@ -167,21 +167,28 @@ export class HttpServer {
for (const router of this.registeredRouters) {
for (const route of router.getRoutes()) {
this.log.debug(`registering route handler for [${route.path}]`);
// Hapi does not allow payload validation to be specified for 'head' or 'get' requests
const validate = isSafeMethod(route.method) ? undefined : { payload: true };
const { authRequired, tags, body = {}, timeout } = route.options;
const { accepts: allow, maxBytes, output, parse } = body;

const kibanaRouteOptions: KibanaRouteOptions = {
xsrfRequired: route.options.xsrfRequired ?? !isSafeMethod(route.method),
};

const routeOpts: ServerRoute = {
this.server.route({
handler: route.handler,
method: route.method,
path: route.path,
options: {
auth: this.getAuthOption(authRequired),
app: kibanaRouteOptions,
tags: tags ? Array.from(tags) : undefined,
// TODO: This 'validate' section can be removed once the legacy platform is completely removed.
// We are telling Hapi that NP routes can accept any payload, so that it can bypass the default
// validation applied in ./http_tools#getServerOptions
// (All NP routes are already required to specify their own validation in order to access the payload)
validate,
// @ts-expect-error Types are outdated and doesn't allow `payload.multipart` to be `true`
payload: [allow, maxBytes, output, parse, timeout?.payload].some((x) => x !== undefined)
? {
Expand All @@ -197,22 +204,7 @@ export class HttpServer {
socket: timeout?.idleSocket ?? this.config!.socketTimeout,
},
},
};

// Hapi does not allow payload validation to be specified for 'head' or 'get' requests
if (!isSafeMethod(route.method)) {
// TODO: This 'validate' section can be removed once the legacy platform is completely removed.
// We are telling Hapi that NP routes can accept any payload, so that it can bypass the default
// validation applied in ./http_tools#getServerOptions
// (All NP routes are already required to specify their own validation in order to access the payload)
// TODO: Move the setting of the validate option back up to being set at `routeOpts` creation-time once
// https://github.com/hapijs/hoek/pull/365 is merged and released in @hapi/hoek v9.1.1. At that point I
// imagine the ts-error below will go away as well.
// @ts-expect-error "Property 'validate' does not exist on type 'RouteOptions'" <-- ehh?!? yes it does!
routeOpts.options!.validate = { payload: true };
}

this.server.route(routeOpts);
});
}
}

Expand Down
14 changes: 11 additions & 3 deletions src/plugins/data/public/ui/filter_bar/filter_item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,27 @@ export function FilterItem(props: Props) {

useEffect(() => {
const index = props.filter.meta.index;
let isSubscribed = true;
if (index) {
getIndexPatterns()
.get(index)
.then((indexPattern) => {
setIndexPatternExists(!!indexPattern);
if (isSubscribed) {
setIndexPatternExists(!!indexPattern);
}
})
.catch(() => {
setIndexPatternExists(false);
if (isSubscribed) {
setIndexPatternExists(false);
}
});
} else {
} else if (isSubscribed) {
// Allow filters without an index pattern and don't validate them.
setIndexPatternExists(true);
}
return () => {
isSubscribed = false;
};
}, [props.filter.meta.index]);

function handleBadgeClick(e: MouseEvent<HTMLInputElement>) {
Expand Down
13 changes: 1 addition & 12 deletions src/plugins/discover/public/application/angular/context_app.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
<kbn-top-nav
app-name="'context'"
show-search-bar="true"
show-filter-bar="true"
show-query-bar="false"
show-save-query="false"
show-date-picker="false"
index-patterns="[contextApp.indexPattern]"
use-default-behaviors="true"
>
</kbn-top-nav>

<!-- Context App Legacy -->
<context-app-legacy
filter="contextApp.actions.addFilter"
Expand All @@ -29,4 +17,5 @@
successor-available="contextApp.state.rows.successors.length"
successor-status="contextApp.state.loadingStatus.successors.status"
on-change-successor-count="contextApp.actions.fetchGivenSuccessorRows"
top-nav-menu="contextApp.topNavMenu"
></context-app-legacy>
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ getAngularModule().directive('contextApp', function ContextApp() {
});

function ContextAppController($scope, Private) {
const { filterManager, indexPatterns, uiSettings } = getServices();
const { filterManager, indexPatterns, uiSettings, navigation } = getServices();
const queryParameterActions = getQueryParameterActions(filterManager, indexPatterns);
const queryActions = Private(QueryActionsProvider);
this.state = createInitialState(
parseInt(uiSettings.get(CONTEXT_STEP_SETTING), 10),
getFirstSortableField(this.indexPattern, uiSettings.get(CONTEXT_TIE_BREAKER_FIELDS_SETTING))
);
this.topNavMenu = navigation.ui.TopNavMenu;

this.actions = _.mapValues(
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React from 'react';

export const TopNavMenuMock = () => <div>Hello World</div>;
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { DocTableLegacy } from '../../angular/doc_table/create_doc_table_react';
import { findTestSubject } from '@elastic/eui/lib/test';
import { ActionBar } from '../../angular/context/components/action_bar/action_bar';
import { ContextErrorMessage } from '../context_error_message';
import { TopNavMenuMock } from './__mocks__/top_nav_menu';

describe('ContextAppLegacy test', () => {
const hit = {
Expand Down Expand Up @@ -64,6 +65,17 @@ describe('ContextAppLegacy test', () => {
onChangeSuccessorCount: jest.fn(),
predecessorStatus: 'loaded',
successorStatus: 'loaded',
topNavMenu: TopNavMenuMock,
};
const topNavProps = {
appName: 'context',
showSearchBar: true,
showQueryBar: false,
showFilterBar: true,
showSaveQuery: false,
showDatePicker: false,
indexPatterns: [indexPattern],
useDefaultBehaviors: true,
};

it('renders correctly', () => {
Expand All @@ -72,6 +84,9 @@ describe('ContextAppLegacy test', () => {
const loadingIndicator = findTestSubject(component, 'contextApp_loadingIndicator');
expect(loadingIndicator.length).toBe(0);
expect(component.find(ActionBar).length).toBe(2);
const topNavMenu = component.find(TopNavMenuMock);
expect(topNavMenu.length).toBe(1);
expect(topNavMenu.props()).toStrictEqual(topNavProps);
});

it('renders loading indicator', () => {
Expand All @@ -82,6 +97,7 @@ describe('ContextAppLegacy test', () => {
const loadingIndicator = findTestSubject(component, 'contextApp_loadingIndicator');
expect(loadingIndicator.length).toBe(1);
expect(component.find(ActionBar).length).toBe(2);
expect(component.find(TopNavMenuMock).length).toBe(1);
});

it('renders error message', () => {
Expand All @@ -90,6 +106,7 @@ describe('ContextAppLegacy test', () => {
props.reason = 'something went wrong';
const component = mountWithIntl(<ContextAppLegacy {...props} />);
expect(component.find(DocTableLegacy).length).toBe(0);
expect(component.find(TopNavMenuMock).length).toBe(0);
const errorMessage = component.find(ContextErrorMessage);
expect(errorMessage.length).toBe(1);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ import {
import { IIndexPattern, IndexPatternField } from '../../../../../data/common/index_patterns';
import { LOADING_STATUS } from './constants';
import { ActionBar, ActionBarProps } from '../../angular/context/components/action_bar/action_bar';
import { TopNavMenuProps } from '../../../../../navigation/public';

export interface ContextAppProps {
topNavMenu: React.ComponentType<TopNavMenuProps>;
columns: string[];
hits: Array<Record<string, unknown>>;
indexPattern: IIndexPattern;
Expand Down Expand Up @@ -96,6 +98,20 @@ export function ContextAppLegacy(renderProps: ContextAppProps) {
} as DocTableLegacyProps;
};

const TopNavMenu = renderProps.topNavMenu;
const getNavBarProps = () => {
return {
appName: 'context',
showSearchBar: true,
showQueryBar: false,
showFilterBar: true,
showSaveQuery: false,
showDatePicker: false,
indexPatterns: [renderProps.indexPattern],
useDefaultBehaviors: true,
};
};

const loadingFeedback = () => {
if (status === LOADING_STATUS.UNINITIALIZED || status === LOADING_STATUS.LOADING) {
return (
Expand All @@ -112,20 +128,23 @@ export function ContextAppLegacy(renderProps: ContextAppProps) {
{isFailed ? (
<ContextErrorMessage status={status} reason={renderProps.reason} />
) : (
<EuiPage>
<EuiPageContent paddingSize="s" className="dscCxtAppContent">
<ActionBar {...actionBarProps(PREDECESSOR_TYPE)} />
{loadingFeedback()}
<EuiHorizontalRule margin="xs" />
{isLoaded ? (
<div className="discover-table">
<DocTableLegacy {...docTableProps()} />
</div>
) : null}
<EuiHorizontalRule margin="xs" />
<ActionBar {...actionBarProps(SUCCESSOR_TYPE)} />
</EuiPageContent>
</EuiPage>
<div>
<TopNavMenu {...getNavBarProps()} />
<EuiPage>
<EuiPageContent paddingSize="s" className="dscCxtAppContent">
<ActionBar {...actionBarProps(PREDECESSOR_TYPE)} />
{loadingFeedback()}
<EuiHorizontalRule margin="xs" />
{isLoaded ? (
<div className="discover-table">
<DocTableLegacy {...docTableProps()} />
</div>
) : null}
<EuiHorizontalRule margin="xs" />
<ActionBar {...actionBarProps(SUCCESSOR_TYPE)} />
</EuiPageContent>
</EuiPage>
</div>
)}
</I18nProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ export function createContextAppLegacy(reactDirective: any) {
['successorAvailable', { watchDepth: 'reference' }],
['successorStatus', { watchDepth: 'reference' }],
['onChangeSuccessorCount', { watchDepth: 'reference' }],
['topNavMenu', { watchDepth: 'reference' }],
]);
}
11 changes: 0 additions & 11 deletions src/plugins/discover/public/get_inner_angular.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ import {
PromiseServiceCreator,
registerListenEventListener,
watchMultiDecorator,
createTopNavDirective,
createTopNavHelper,
} from '../../kibana_legacy/public';
import { DiscoverStartPlugins } from './plugin';
import { getScopedHistory } from './kibana_services';
Expand Down Expand Up @@ -98,7 +96,6 @@ export function initializeInnerAngularModule(
createLocalI18nModule();
createLocalPrivateModule();
createLocalPromiseModule();
createLocalTopNavModule(navigation);
createLocalStorageModule();
createPagerFactoryModule();
createDocTableModule();
Expand Down Expand Up @@ -131,7 +128,6 @@ export function initializeInnerAngularModule(
'discoverI18n',
'discoverPrivate',
'discoverPromise',
'discoverTopNav',
'discoverLocalStorageProvider',
'discoverDocTable',
'discoverPagerFactory',
Expand All @@ -151,13 +147,6 @@ function createLocalPrivateModule() {
angular.module('discoverPrivate', []).provider('Private', PrivateProvider);
}

function createLocalTopNavModule(navigation: NavigationStart) {
angular
.module('discoverTopNav', ['react'])
.directive('kbnTopNav', createTopNavDirective)
.directive('kbnTopNavHelper', createTopNavHelper(navigation.ui));
}

function createLocalI18nModule() {
angular
.module('discoverI18n', [])
Expand Down
Loading

0 comments on commit 2a6708d

Please sign in to comment.