Skip to content

Commit

Permalink
Merge branch 'master' into alerts/action-groups-as-conditions
Browse files Browse the repository at this point in the history
* master:
  Migrate `/translations` route to core (elastic#83280)
  [APM] Ensure APM jest script can run (elastic#83398)
  [Uptime] Monitor status alert use url as instance (elastic#81736)
  [ML] Add basic license test run details to ML+Transform READMEs (elastic#83259)
  TSVB doesn't communicate it's index-patterns to dashboard (elastic#82964)
  [Alerting UI] Added ability to assign alert actions to resolved action group in UI (elastic#83139)
  Skips Vega test
  skip flaky suite (elastic#79967)
  [bundle optimization] Update to semver 7.x to get tree-shaking (elastic#83020)
  Added ability to fire actions when an alert instance is resolved (elastic#82799)
  [ML] Adds functional tests for the index data visualizer card contents (elastic#83174)
  • Loading branch information
gmmorris committed Nov 16, 2020
2 parents f809c8b + d1abc86 commit c54458f
Show file tree
Hide file tree
Showing 81 changed files with 3,835 additions and 1,328 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@
"rison-node": "1.0.2",
"rxjs": "^6.5.5",
"seedrandom": "^3.0.5",
"semver": "^5.7.0",
"semver": "^7.3.2",
"set-value": "^3.0.2",
"source-map-support": "^0.5.19",
"squel": "^5.13.0",
Expand Down Expand Up @@ -536,7 +536,7 @@
"@types/request": "^2.48.2",
"@types/seedrandom": ">=2.0.0 <4.0.0",
"@types/selenium-webdriver": "^4.0.9",
"@types/semver": "^5.5.0",
"@types/semver": "^7",
"@types/set-value": "^2.0.0",
"@types/sinon": "^7.0.13",
"@types/source-map-support": "^0.5.3",
Expand Down
3,507 changes: 2,498 additions & 1,009 deletions packages/kbn-pm/dist/index.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/core/server/i18n/i18n_service.test.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ export const initTranslationsMock = jest.fn();
jest.doMock('./init_translations', () => ({
initTranslations: initTranslationsMock,
}));

export const registerRoutesMock = jest.fn();
jest.doMock('./routes', () => ({
registerRoutes: registerRoutesMock,
}));
26 changes: 22 additions & 4 deletions src/core/server/i18n/i18n_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@
* under the License.
*/

import { getKibanaTranslationFilesMock, initTranslationsMock } from './i18n_service.test.mocks';
import {
getKibanaTranslationFilesMock,
initTranslationsMock,
registerRoutesMock,
} from './i18n_service.test.mocks';

import { BehaviorSubject } from 'rxjs';
import { I18nService } from './i18n_service';

import { configServiceMock } from '../config/mocks';
import { mockCoreContext } from '../core_context.mock';
import { httpServiceMock } from '../http/http_service.mock';

const getConfigService = (locale = 'en') => {
const configService = configServiceMock.create();
Expand All @@ -41,21 +46,24 @@ const getConfigService = (locale = 'en') => {
describe('I18nService', () => {
let service: I18nService;
let configService: ReturnType<typeof configServiceMock.create>;
let http: ReturnType<typeof httpServiceMock.createInternalSetupContract>;

beforeEach(() => {
jest.clearAllMocks();
configService = getConfigService();

const coreContext = mockCoreContext.create({ configService });
service = new I18nService(coreContext);

http = httpServiceMock.createInternalSetupContract();
});

describe('#setup', () => {
it('calls `getKibanaTranslationFiles` with the correct parameters', async () => {
getKibanaTranslationFilesMock.mockResolvedValue([]);

const pluginPaths = ['/pathA', '/pathB'];
await service.setup({ pluginPaths });
await service.setup({ pluginPaths, http });

expect(getKibanaTranslationFilesMock).toHaveBeenCalledTimes(1);
expect(getKibanaTranslationFilesMock).toHaveBeenCalledWith('en', pluginPaths);
Expand All @@ -65,17 +73,27 @@ describe('I18nService', () => {
const translationFiles = ['/path/to/file', 'path/to/another/file'];
getKibanaTranslationFilesMock.mockResolvedValue(translationFiles);

await service.setup({ pluginPaths: [] });
await service.setup({ pluginPaths: [], http });

expect(initTranslationsMock).toHaveBeenCalledTimes(1);
expect(initTranslationsMock).toHaveBeenCalledWith('en', translationFiles);
});

it('calls `registerRoutesMock` with the correct parameters', async () => {
await service.setup({ pluginPaths: [], http });

expect(registerRoutesMock).toHaveBeenCalledTimes(1);
expect(registerRoutesMock).toHaveBeenCalledWith({
locale: 'en',
router: expect.any(Object),
});
});

it('returns accessors for locale and translation files', async () => {
const translationFiles = ['/path/to/file', 'path/to/another/file'];
getKibanaTranslationFilesMock.mockResolvedValue(translationFiles);

const { getLocale, getTranslationFiles } = await service.setup({ pluginPaths: [] });
const { getLocale, getTranslationFiles } = await service.setup({ pluginPaths: [], http });

expect(getLocale()).toEqual('en');
expect(getTranslationFiles()).toEqual(translationFiles);
Expand Down
8 changes: 7 additions & 1 deletion src/core/server/i18n/i18n_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ import { take } from 'rxjs/operators';
import { Logger } from '../logging';
import { IConfigService } from '../config';
import { CoreContext } from '../core_context';
import { InternalHttpServiceSetup } from '../http';
import { config as i18nConfigDef, I18nConfigType } from './i18n_config';
import { getKibanaTranslationFiles } from './get_kibana_translation_files';
import { initTranslations } from './init_translations';
import { registerRoutes } from './routes';

interface SetupDeps {
http: InternalHttpServiceSetup;
pluginPaths: string[];
}

Expand Down Expand Up @@ -53,7 +56,7 @@ export class I18nService {
this.configService = coreContext.configService;
}

public async setup({ pluginPaths }: SetupDeps): Promise<I18nServiceSetup> {
public async setup({ pluginPaths, http }: SetupDeps): Promise<I18nServiceSetup> {
const i18nConfig = await this.configService
.atPath<I18nConfigType>(i18nConfigDef.path)
.pipe(take(1))
Expand All @@ -67,6 +70,9 @@ export class I18nService {
this.log.debug(`Using translation files: [${translationFiles.join(', ')}]`);
await initTranslations(locale, translationFiles);

const router = http.createRouter('');
registerRoutes({ router, locale });

return {
getLocale: () => locale,
getTranslationFiles: () => translationFiles,
Expand Down
25 changes: 25 additions & 0 deletions src/core/server/i18n/routes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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 { IRouter } from '../../http';
import { registerTranslationsRoute } from './translations';

export const registerRoutes = ({ router, locale }: { router: IRouter; locale: string }) => {
registerTranslationsRoute(router, locale);
};
69 changes: 69 additions & 0 deletions src/core/server/i18n/routes/translations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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 { createHash } from 'crypto';
import { i18n } from '@kbn/i18n';
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';

interface TranslationCache {
translations: string;
hash: string;
}

export const registerTranslationsRoute = (router: IRouter, locale: string) => {
let translationCache: TranslationCache;

router.get(
{
path: '/translations/{locale}.json',
validate: {
params: schema.object({
locale: schema.string(),
}),
},
options: {
authRequired: false,
},
},
(ctx, req, res) => {
if (req.params.locale.toLowerCase() !== locale.toLowerCase()) {
return res.notFound({
body: `Unknown locale: ${req.params.locale}`,
});
}
if (!translationCache) {
const translations = JSON.stringify(i18n.getTranslation());
const hash = createHash('sha1').update(translations).digest('hex');
translationCache = {
translations,
hash,
};
}
return res.ok({
headers: {
'content-type': 'application/json',
'cache-control': 'must-revalidate',
etag: translationCache.hash,
},
body: translationCache.translations,
});
}
);
};
6 changes: 3 additions & 3 deletions src/core/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,6 @@ export class Server {
await ensureValidConfiguration(this.configService, legacyConfigSetup);
}

// setup i18n prior to any other service, to have translations ready
const i18nServiceSetup = await this.i18n.setup({ pluginPaths });

const contextServiceSetup = this.context.setup({
// We inject a fake "legacy plugin" with dependencies on every plugin so that legacy plugins:
// 1) Can access context from any KP plugin
Expand All @@ -149,6 +146,9 @@ export class Server {
context: contextServiceSetup,
});

// setup i18n prior to any other service, to have translations ready
const i18nServiceSetup = await this.i18n.setup({ http: httpSetup, pluginPaths });

const capabilitiesSetup = this.capabilities.setup({ http: httpSetup });

const elasticsearchServiceSetup = await this.elasticsearch.setup({
Expand Down
32 changes: 0 additions & 32 deletions src/legacy/ui/ui_render/ui_render_mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
* under the License.
*/

import { createHash } from 'crypto';
import Boom from '@hapi/boom';
import { i18n } from '@kbn/i18n';
import * as UiSharedDeps from '@kbn/ui-shared-deps';
import { KibanaRequest } from '../../../core/server';
import { AppBootstrap } from './bootstrap';
Expand All @@ -37,36 +35,6 @@ import { getApmConfig } from '../apm';
* @param {KbnServer['config']} config
*/
export function uiRenderMixin(kbnServer, server, config) {
const translationsCache = { translations: null, hash: null };
server.route({
path: '/translations/{locale}.json',
method: 'GET',
config: { auth: false },
handler(request, h) {
// Kibana server loads translations only for a single locale
// that is specified in `i18n.locale` config value.
const { locale } = request.params;
if (i18n.getLocale() !== locale.toLowerCase()) {
throw Boom.notFound(`Unknown locale: ${locale}`);
}

// Stringifying thousands of labels and calculating hash on the resulting
// string can be expensive so it makes sense to do it once and cache.
if (translationsCache.translations == null) {
translationsCache.translations = JSON.stringify(i18n.getTranslation());
translationsCache.hash = createHash('sha1')
.update(translationsCache.translations)
.digest('hex');
}

return h
.response(translationsCache.translations)
.header('cache-control', 'must-revalidate')
.header('content-type', 'application/json')
.etag(translationsCache.hash);
},
});

const authEnabled = !!server.auth.settings.default;
server.route({
path: '/bootstrap.js',
Expand Down
12 changes: 6 additions & 6 deletions src/plugins/dashboard/common/migrate_to_730_panels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/
import { i18n } from '@kbn/i18n';
import semver from 'semver';
import semverSatisfies from 'semver/functions/satisfies';
import uuid from 'uuid';
import {
GridData,
Expand Down Expand Up @@ -60,23 +60,23 @@ function isPre61Panel(
}

function is61Panel(panel: unknown | RawSavedDashboardPanel610): panel is RawSavedDashboardPanel610 {
return semver.satisfies((panel as RawSavedDashboardPanel610).version, '6.1.x');
return semverSatisfies((panel as RawSavedDashboardPanel610).version, '6.1.x');
}

function is62Panel(panel: unknown | RawSavedDashboardPanel620): panel is RawSavedDashboardPanel620 {
return semver.satisfies((panel as RawSavedDashboardPanel620).version, '6.2.x');
return semverSatisfies((panel as RawSavedDashboardPanel620).version, '6.2.x');
}

function is63Panel(panel: unknown | RawSavedDashboardPanel630): panel is RawSavedDashboardPanel630 {
return semver.satisfies((panel as RawSavedDashboardPanel630).version, '6.3.x');
return semverSatisfies((panel as RawSavedDashboardPanel630).version, '6.3.x');
}

function is640To720Panel(
panel: unknown | RawSavedDashboardPanel640To720
): panel is RawSavedDashboardPanel640To720 {
return (
semver.satisfies((panel as RawSavedDashboardPanel630).version, '>6.3') &&
semver.satisfies((panel as RawSavedDashboardPanel630).version, '<7.3')
semverSatisfies((panel as RawSavedDashboardPanel630).version, '>6.3') &&
semverSatisfies((panel as RawSavedDashboardPanel630).version, '<7.3')
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/

import semver from 'semver';
import semverSatisfies from 'semver/functions/satisfies';
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';

Expand Down Expand Up @@ -68,7 +68,7 @@ export function migrateAppState(
usageCollection.reportUiStats('DashboardPanelVersionInUrl', METRIC_TYPE.LOADED, `${version}`);
}

return semver.satisfies(version, '<7.3');
return semverSatisfies(version, '<7.3');
});

if (panelNeedsMigration) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
* under the License.
*/

import semver from 'semver';
import SemVer from 'semver/classes/semver';
import semverParse from 'semver/functions/parse';
import { TelemetrySavedObject } from './types';

interface GetTelemetryOptInConfig {
Expand Down Expand Up @@ -80,10 +81,10 @@ export const getTelemetryOptIn: GetTelemetryOptIn = ({
return savedOptIn;
};

function parseSemver(version: string): semver.SemVer | null {
function parseSemver(version: string): SemVer | null {
// semver functions both return nulls AND throw exceptions: "it depends!"
try {
return semver.parse(version);
return semverParse(version);
} catch (err) {
return null;
}
Expand Down
1 change: 1 addition & 0 deletions src/plugins/vis_type_timeseries/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
*/

export const MAX_BUCKETS_SETTING = 'metrics:max_buckets';
export const INDEXES_SEPARATOR = ',';
Loading

0 comments on commit c54458f

Please sign in to comment.