[7.x] Remove Newsfeed leftovers from the Legacy codebase (#66084) (#66427)

This commit is contained in:
Alejandro Fernández Haro 2020-05-13 18:45:02 +01:00 committed by GitHub
parent c63d600350
commit fa4cd2c152
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 255 additions and 386 deletions

View file

@ -1,71 +0,0 @@
/*
* 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 { resolve } from 'path';
import { LegacyPluginApi, LegacyPluginSpec, ArrayOrItem } from 'src/legacy/plugin_discovery/types';
import { Legacy } from 'kibana';
import { NewsfeedPluginInjectedConfig } from '../../../plugins/newsfeed/types';
import {
PLUGIN_ID,
DEFAULT_SERVICE_URLROOT,
DEV_SERVICE_URLROOT,
DEFAULT_SERVICE_PATH,
} from './constants';
// eslint-disable-next-line import/no-default-export
export default function(kibana: LegacyPluginApi): ArrayOrItem<LegacyPluginSpec> {
const pluginSpec: Legacy.PluginSpecOptions = {
id: PLUGIN_ID,
config(Joi: any) {
// NewsfeedPluginInjectedConfig in Joi form
return Joi.object({
enabled: Joi.boolean().default(true),
service: Joi.object({
pathTemplate: Joi.string().default(DEFAULT_SERVICE_PATH),
urlRoot: Joi.when('$prod', {
is: true,
then: Joi.string().default(DEFAULT_SERVICE_URLROOT),
otherwise: Joi.string().default(DEV_SERVICE_URLROOT),
}),
}).default(),
defaultLanguage: Joi.string().default('en'),
mainInterval: Joi.number().default(120 * 1000), // (2min) How often to retry failed fetches, and/or check if newsfeed items need to be refreshed from remote
fetchInterval: Joi.number().default(86400 * 1000), // (1day) How often to fetch remote and reset the last fetched time
}).default();
},
uiExports: {
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
injectDefaultVars(server): NewsfeedPluginInjectedConfig {
const config = server.config();
return {
newsfeed: {
service: {
pathTemplate: config.get('newsfeed.service.pathTemplate') as string,
urlRoot: config.get('newsfeed.service.urlRoot') as string,
},
defaultLanguage: config.get('newsfeed.defaultLanguage') as string,
mainInterval: config.get('newsfeed.mainInterval') as number,
fetchInterval: config.get('newsfeed.fetchInterval') as number,
},
};
},
},
};
return new kibana.Plugin(pluginSpec);
}

View file

@ -1,4 +0,0 @@
{
"name": "newsfeed",
"version": "kibana"
}

View file

@ -1,3 +0,0 @@
@import 'src/legacy/ui/public/styles/styling_constants';
@import './np_ready/components/header_alert/_index';

View file

@ -1,27 +0,0 @@
@import '@elastic/eui/src/components/header/variables';
.kbnNews__flyout {
top: $euiHeaderChildSize + 1px;
height: calc(100% - #{$euiHeaderChildSize});
}
.kbnNewsFeed__headerAlert.euiHeaderAlert {
margin-bottom: $euiSizeL;
padding: 0 $euiSizeS $euiSizeL;
border-bottom: $euiBorderThin;
border-top: none;
.euiHeaderAlert__title {
@include euiTitle('xs');
margin-bottom: $euiSizeS;
}
.euiHeaderAlert__text {
@include euiFontSizeS;
margin-bottom: $euiSize;
}
.euiHeaderAlert__action {
@include euiFontSizeS;
}
}

View file

@ -1,76 +0,0 @@
/*
* 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';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { EuiFlexGroup, EuiFlexItem, EuiI18n } from '@elastic/eui';
interface IEuiHeaderAlertProps {
action: JSX.Element;
className?: string;
date: string;
text: string;
title: string;
badge?: JSX.Element;
rest?: string[];
}
export const EuiHeaderAlert = ({
action,
className,
date,
text,
title,
badge,
...rest
}: IEuiHeaderAlertProps) => {
const classes = classNames('euiHeaderAlert', 'kbnNewsFeed__headerAlert', className);
const badgeContent = badge || null;
return (
<EuiI18n token="euiHeaderAlert.dismiss" default="Dismiss">
{(dismiss: any) => (
<div className={classes} {...rest}>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem>
<div className="euiHeaderAlert__date">{date}</div>
</EuiFlexItem>
<EuiFlexItem grow={false}>{badgeContent}</EuiFlexItem>
</EuiFlexGroup>
<div className="euiHeaderAlert__title">{title}</div>
<div className="euiHeaderAlert__text">{text}</div>
<div className="euiHeaderAlert__action euiLink">{action}</div>
</div>
)}
</EuiI18n>
);
};
EuiHeaderAlert.propTypes = {
action: PropTypes.node,
className: PropTypes.string,
date: PropTypes.node.isRequired,
text: PropTypes.node,
title: PropTypes.node.isRequired,
badge: PropTypes.node,
};

View file

@ -17,17 +17,10 @@
* under the License.
*/
import Hapi from 'hapi';
import { initPlugin as initNewsfeed } from './newsfeed_simulation';
export const NEWSFEED_FALLBACK_LANGUAGE = 'en';
export const NEWSFEED_LAST_FETCH_STORAGE_KEY = 'newsfeed.lastfetchtime';
export const NEWSFEED_HASH_SET_STORAGE_KEY = 'newsfeed.hashes';
const NAME = 'newsfeed-FTS-external-service-simulators';
// eslint-disable-next-line import/no-default-export
export default function(kibana: any) {
return new kibana.Plugin({
name: NAME,
init: (server: Hapi.Server) => {
initNewsfeed(server, `/api/_${NAME}`);
},
});
}
export const NEWSFEED_DEFAULT_SERVICE_BASE_URL = 'https://feeds.elastic.co';
export const NEWSFEED_DEV_SERVICE_BASE_URL = 'https://feeds-staging.elastic.co';
export const NEWSFEED_DEFAULT_SERVICE_PATH = '/kibana/v{VERSION}.json';

View file

@ -1,6 +1,6 @@
{
"id": "newsfeed",
"version": "kibana",
"server": false,
"server": true,
"ui": true
}

View file

@ -29,11 +29,11 @@ import {
EuiButtonEmpty,
EuiText,
EuiBadge,
EuiHeaderAlert,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiHeaderAlert } from '../../../../legacy/core_plugins/newsfeed/public/np_ready/components/header_alert/header_alert';
import { NewsfeedContext } from './newsfeed_header_nav_button';
import { NewsfeedItem } from '../../types';
import { NewsfeedItem } from '../types';
import { NewsEmptyPrompt } from './empty_news';
import { NewsLoadingPrompt } from './loading_news';

View file

@ -21,7 +21,7 @@ import React, { useState, Fragment, useEffect } from 'react';
import * as Rx from 'rxjs';
import { EuiHeaderSectionItemButton, EuiIcon, EuiNotificationBadge } from '@elastic/eui';
import { NewsfeedFlyout } from './flyout_list';
import { FetchResult } from '../../types';
import { FetchResult } from '../types';
export interface INewsfeedContext {
setFlyoutVisible: React.Dispatch<React.SetStateAction<boolean>>;

View file

@ -22,8 +22,11 @@ import { interval, race } from 'rxjs';
import sinon, { stub } from 'sinon';
import moment from 'moment';
import { HttpSetup } from 'src/core/public';
import { NEWSFEED_HASH_SET_STORAGE_KEY, NEWSFEED_LAST_FETCH_STORAGE_KEY } from '../../constants';
import { ApiItem, NewsfeedItem, NewsfeedPluginInjectedConfig } from '../../types';
import {
NEWSFEED_HASH_SET_STORAGE_KEY,
NEWSFEED_LAST_FETCH_STORAGE_KEY,
} from '../../common/constants';
import { ApiItem, NewsfeedItem, NewsfeedPluginBrowserConfig } from '../types';
import { NewsfeedApiDriver, getApi } from './api';
const localStorageGet = sinon.stub();
@ -458,7 +461,7 @@ describe('getApi', () => {
}
return Promise.reject('wrong args!');
};
let configMock: NewsfeedPluginInjectedConfig;
let configMock: NewsfeedPluginBrowserConfig;
afterEach(() => {
jest.resetAllMocks();
@ -466,15 +469,12 @@ describe('getApi', () => {
beforeEach(() => {
configMock = {
newsfeed: {
service: {
urlRoot: 'http://fakenews.co',
pathTemplate: '/kibana-test/v{VERSION}.json',
},
defaultLanguage: 'en',
mainInterval: 86400000,
fetchInterval: 86400000,
service: {
urlRoot: 'http://fakenews.co',
pathTemplate: '/kibana-test/v{VERSION}.json',
},
mainInterval: moment.duration(86400000),
fetchInterval: moment.duration(86400000),
};
httpMock = ({
fetch: mockHttpGet,
@ -483,7 +483,7 @@ describe('getApi', () => {
it('creates a result', done => {
mockHttpGet.mockImplementationOnce(() => Promise.resolve({ items: [] }));
getApi(httpMock, configMock.newsfeed, '6.8.2').subscribe(result => {
getApi(httpMock, configMock, '6.8.2').subscribe(result => {
expect(result).toMatchInlineSnapshot(`
Object {
"error": null,
@ -528,7 +528,7 @@ describe('getApi', () => {
mockHttpGet.mockImplementationOnce(getHttpMockWithItems(mockApiItems));
getApi(httpMock, configMock.newsfeed, '6.8.2').subscribe(result => {
getApi(httpMock, configMock, '6.8.2').subscribe(result => {
expect(result).toMatchInlineSnapshot(`
Object {
"error": null,
@ -568,7 +568,7 @@ describe('getApi', () => {
},
];
mockHttpGet.mockImplementationOnce(getHttpMockWithItems(mockApiItems));
getApi(httpMock, configMock.newsfeed, '6.8.2').subscribe(result => {
getApi(httpMock, configMock, '6.8.2').subscribe(result => {
expect(result).toMatchInlineSnapshot(`
Object {
"error": null,
@ -595,7 +595,7 @@ describe('getApi', () => {
it('forwards an error', done => {
mockHttpGet.mockImplementationOnce((arg1, arg2) => Promise.reject('sorry, try again later!'));
getApi(httpMock, configMock.newsfeed, '6.8.2').subscribe(result => {
getApi(httpMock, configMock, '6.8.2').subscribe(result => {
expect(result).toMatchInlineSnapshot(`
Object {
"error": "sorry, try again later!",
@ -623,14 +623,14 @@ describe('getApi', () => {
];
it("retries until fetch doesn't error", done => {
configMock.newsfeed.mainInterval = 10; // fast retry for testing
configMock.mainInterval = moment.duration(10); // fast retry for testing
mockHttpGet
.mockImplementationOnce(() => Promise.reject('Sorry, try again later!'))
.mockImplementationOnce(() => Promise.reject('Sorry, internal server error!'))
.mockImplementationOnce(() => Promise.reject("Sorry, it's too cold to go outside!"))
.mockImplementationOnce(getHttpMockWithItems(successItems));
getApi(httpMock, configMock.newsfeed, '6.8.2')
getApi(httpMock, configMock, '6.8.2')
.pipe(take(4), toArray())
.subscribe(result => {
expect(result).toMatchInlineSnapshot(`
@ -677,13 +677,13 @@ describe('getApi', () => {
});
it("doesn't retry if fetch succeeds", done => {
configMock.newsfeed.mainInterval = 10; // fast retry for testing
configMock.mainInterval = moment.duration(10); // fast retry for testing
mockHttpGet.mockImplementation(getHttpMockWithItems(successItems));
const timeout$ = interval(1000); // lets us capture some results after a short time
let timesFetched = 0;
const get$ = getApi(httpMock, configMock.newsfeed, '6.8.2').pipe(
const get$ = getApi(httpMock, configMock, '6.8.2').pipe(
tap(() => {
timesFetched++;
})

View file

@ -26,10 +26,10 @@ import {
NEWSFEED_FALLBACK_LANGUAGE,
NEWSFEED_LAST_FETCH_STORAGE_KEY,
NEWSFEED_HASH_SET_STORAGE_KEY,
} from '../../constants';
import { NewsfeedPluginInjectedConfig, ApiItem, NewsfeedItem, FetchResult } from '../../types';
} from '../../common/constants';
import { ApiItem, NewsfeedItem, FetchResult, NewsfeedPluginBrowserConfig } from '../types';
type ApiConfig = NewsfeedPluginInjectedConfig['newsfeed']['service'];
type ApiConfig = NewsfeedPluginBrowserConfig['service'];
export class NewsfeedApiDriver {
private readonly loadedTime = moment().utc(); // the date is compared to time in UTC format coming from the service
@ -167,14 +167,14 @@ export class NewsfeedApiDriver {
*/
export function getApi(
http: HttpSetup,
config: NewsfeedPluginInjectedConfig['newsfeed'],
config: NewsfeedPluginBrowserConfig,
kibanaVersion: string
): Rx.Observable<void | FetchResult> {
const userLanguage = i18n.getLocale() || config.defaultLanguage;
const fetchInterval = config.fetchInterval;
const userLanguage = i18n.getLocale();
const fetchInterval = config.fetchInterval.asMilliseconds();
const driver = new NewsfeedApiDriver(kibanaVersion, userLanguage, fetchInterval);
return Rx.timer(0, config.mainInterval).pipe(
return Rx.timer(0, config.mainInterval.asMilliseconds()).pipe(
filter(() => driver.shouldFetch()),
mergeMap(() =>
driver.fetchNewsfeedItems(http, config.service).pipe(

View file

@ -21,9 +21,10 @@ import * as Rx from 'rxjs';
import { catchError, takeUntil } from 'rxjs/operators';
import ReactDOM from 'react-dom';
import React from 'react';
import moment from 'moment';
import { I18nProvider } from '@kbn/i18n/react';
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public';
import { FetchResult, NewsfeedPluginInjectedConfig } from '../types';
import { NewsfeedPluginBrowserConfig } from './types';
import { NewsfeedNavButton, NewsfeedApiFetchResult } from './components/newsfeed_header_nav_button';
import { getApi } from './lib/api';
@ -32,10 +33,18 @@ export type Start = object;
export class NewsfeedPublicPlugin implements Plugin<Setup, Start> {
private readonly kibanaVersion: string;
private readonly config: NewsfeedPluginBrowserConfig;
private readonly stop$ = new Rx.ReplaySubject(1);
constructor(initializerContext: PluginInitializerContext) {
constructor(initializerContext: PluginInitializerContext<NewsfeedPluginBrowserConfig>) {
this.kibanaVersion = initializerContext.env.packageInfo.version;
const config = initializerContext.config.get();
this.config = Object.freeze({
...config,
// We need wrap them in moment.duration because exposeToBrowser stringifies it.
mainInterval: moment.duration(config.mainInterval),
fetchInterval: moment.duration(config.fetchInterval),
});
}
public setup(core: CoreSetup): Setup {
@ -57,16 +66,8 @@ export class NewsfeedPublicPlugin implements Plugin<Setup, Start> {
}
private fetchNewsfeed(core: CoreStart) {
const { http, injectedMetadata } = core;
const config = injectedMetadata.getInjectedVar('newsfeed') as
| NewsfeedPluginInjectedConfig['newsfeed']
| undefined;
if (!config) {
// running in new platform, injected metadata not available
return new Rx.Observable<void | FetchResult | null>();
}
return getApi(http, config, this.kibanaVersion).pipe(
const { http } = core;
return getApi(http, this.config, this.kibanaVersion).pipe(
takeUntil(this.stop$), // stop the interval when stop method is called
catchError(() => Rx.of(null)) // do not throw error
);

View file

@ -17,18 +17,16 @@
* under the License.
*/
import { Moment } from 'moment';
import { Duration, Moment } from 'moment';
export interface NewsfeedPluginInjectedConfig {
newsfeed: {
service: {
urlRoot: string;
pathTemplate: string;
};
defaultLanguage: string;
mainInterval: number; // how often to check last updated time
fetchInterval: number; // how often to fetch remote service and set last updated
// Ideally, we may want to obtain the type from the configSchema and exposeToBrowser keys...
export interface NewsfeedPluginBrowserConfig {
service: {
urlRoot: string;
pathTemplate: string;
};
mainInterval: Duration; // how often to check last updated time
fetchInterval: Duration; // how often to fetch remote service and set last updated
}
export interface ApiItem {

View file

@ -0,0 +1,44 @@
/*
* 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 { schema, TypeOf } from '@kbn/config-schema';
import {
NEWSFEED_DEFAULT_SERVICE_PATH,
NEWSFEED_DEFAULT_SERVICE_BASE_URL,
NEWSFEED_DEV_SERVICE_BASE_URL,
NEWSFEED_FALLBACK_LANGUAGE,
} from '../common/constants';
export const configSchema = schema.object({
enabled: schema.boolean({ defaultValue: true }),
service: schema.object({
pathTemplate: schema.string({ defaultValue: NEWSFEED_DEFAULT_SERVICE_PATH }),
urlRoot: schema.conditional(
schema.contextRef('prod'),
schema.literal(true), // Point to staging if it's not a production release
schema.string({ defaultValue: NEWSFEED_DEFAULT_SERVICE_BASE_URL }),
schema.string({ defaultValue: NEWSFEED_DEV_SERVICE_BASE_URL })
),
}),
defaultLanguage: schema.string({ defaultValue: NEWSFEED_FALLBACK_LANGUAGE }), // TODO: Deprecate since no longer used
mainInterval: schema.duration({ defaultValue: '2m' }), // (2min) How often to retry failed fetches, and/or check if newsfeed items need to be refreshed from remote
fetchInterval: schema.duration({ defaultValue: '1d' }), // (1day) How often to fetch remote and reset the last fetched time
});
export type NewsfeedConfigType = TypeOf<typeof configSchema>;

View file

@ -0,0 +1,36 @@
/*
* 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 { PluginConfigDescriptor } from 'kibana/server';
import { NewsfeedPlugin } from './plugin';
import { configSchema, NewsfeedConfigType } from './config';
export const config: PluginConfigDescriptor<NewsfeedConfigType> = {
schema: configSchema,
exposeToBrowser: {
service: true,
mainInterval: true,
fetchInterval: true,
},
deprecations: ({ unused }) => [unused('defaultLanguage')],
};
export function plugin() {
return new NewsfeedPlugin();
}

View file

@ -17,6 +17,12 @@
* under the License.
*/
export const NEWSFEED_FALLBACK_LANGUAGE = 'en';
export const NEWSFEED_LAST_FETCH_STORAGE_KEY = 'newsfeed.lastfetchtime';
export const NEWSFEED_HASH_SET_STORAGE_KEY = 'newsfeed.hashes';
import { Plugin } from 'kibana/server';
export class NewsfeedPlugin implements Plugin {
public setup() {}
public start() {}
public stop() {}
}

View file

@ -0,0 +1,6 @@
{
"id": "newsfeed-fixtures",
"version": "kibana",
"server": true,
"ui": false
}

View file

@ -1,126 +0,0 @@
/*
* 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 Hapi from 'hapi';
interface WebhookRequest extends Hapi.Request {
payload: string;
}
export async function initPlugin(server: Hapi.Server, path: string) {
server.route({
method: ['GET'],
path: `${path}/kibana/v{version}.json`,
options: {
cors: {
origin: ['*'],
additionalHeaders: [
'Sec-Fetch-Mode',
'Access-Control-Request-Method',
'Access-Control-Request-Headers',
'cache-control',
'x-requested-with',
'Origin',
'User-Agent',
'DNT',
'content-type',
'kbn-version',
],
},
},
handler: newsfeedHandler as Hapi.Lifecycle.Method,
});
server.route({
method: ['GET'],
path: `${path}/kibana/crash.json`,
options: {
cors: {
origin: ['*'],
additionalHeaders: [
'Sec-Fetch-Mode',
'Access-Control-Request-Method',
'Access-Control-Request-Headers',
'cache-control',
'x-requested-with',
'Origin',
'User-Agent',
'DNT',
'content-type',
'kbn-version',
],
},
},
handler() {
throw new Error('Internal server error');
},
});
}
function newsfeedHandler(request: WebhookRequest, h: any) {
return htmlResponse(h, 200, JSON.stringify(mockNewsfeed(request.params.version)));
}
const mockNewsfeed = (version: string) => ({
items: [
{
title: { en: `You are functionally testing the newsfeed widget with fixtures!` },
description: { en: 'See test/common/fixtures/plugins/newsfeed/newsfeed_simulation' },
link_text: { en: 'Generic feed-viewer could go here' },
link_url: { en: 'https://feeds.elastic.co' },
languages: null,
badge: null,
image_url: null,
publish_on: '2019-06-21T00:00:00',
expire_on: '2040-01-31T00:00:00',
hash: '39ca7d409c7eb25f4c69a5a6a11309b2f5ced7ca3f9b3a0109517126e0fd91ca',
},
{
title: { en: 'Staging too!' },
description: { en: 'Hello world' },
link_text: { en: 'Generic feed-viewer could go here' },
link_url: { en: 'https://feeds-staging.elastic.co' },
languages: null,
badge: null,
image_url: null,
publish_on: '2019-06-21T00:00:00',
expire_on: '2040-01-31T00:00:00',
hash: 'db445c9443eb50ea2eb15f20edf89cf0f7dac2b058b11cafc2c8c288b6e4ce2a',
},
{
title: { en: 'This item is expired!' },
description: { en: 'This should not show up.' },
link_text: { en: 'Generic feed-viewer could go here' },
link_url: { en: 'https://feeds-staging.elastic.co' },
languages: null,
badge: null,
image_url: null,
publish_on: '2019-06-21T00:00:00',
expire_on: '2019-12-31T00:00:00',
hash: 'db445c9443eb50ea2eb15f20edf89cf0f7dac2b058b11cafc2c8c288b6e4ce2a',
},
],
});
function htmlResponse(h: any, code: number, text: string) {
return h
.response(text)
.type('application/json')
.code(code);
}

View file

@ -1,7 +0,0 @@
{
"name": "newsfeed-fixtures",
"version": "0.0.0",
"kibana": {
"version": "kibana"
}
}

View file

@ -17,7 +17,9 @@
* under the License.
*/
export const PLUGIN_ID = 'newsfeed';
export const DEFAULT_SERVICE_URLROOT = 'https://feeds.elastic.co';
export const DEV_SERVICE_URLROOT = 'https://feeds-staging.elastic.co';
export const DEFAULT_SERVICE_PATH = '/kibana/v{VERSION}.json';
import { PluginInitializerContext } from 'kibana/public';
import { NewsFeedSimulatorPlugin } from './plugin';
export function plugin(initializerContext: PluginInitializerContext) {
return new NewsFeedSimulatorPlugin(initializerContext);
}

View file

@ -0,0 +1,97 @@
/*
* 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 { CoreSetup, Plugin } from 'kibana/server';
import { PluginInitializerContext } from 'kibana/public';
export class NewsFeedSimulatorPlugin implements Plugin {
constructor(private readonly initializerContext: PluginInitializerContext) {}
public setup({ http }: CoreSetup) {
const router = http.createRouter();
const version = this.initializerContext.env.packageInfo.version;
router.get(
{
path: `/api/_newsfeed-FTS-external-service-simulators/kibana/v${version}.json`,
validate: false,
options: { authRequired: false },
},
(context, req, res) => {
return res.ok({ body: this.mockNewsfeed() });
}
);
router.get(
{
path: '/api/_newsfeed-FTS-external-service-simulators/kibana/crash.json',
validate: false,
options: { authRequired: false },
},
(context, req, res) => {
return res.internalError({ body: new Error('Internal server error') });
}
);
}
public start() {}
private mockNewsfeed() {
return {
items: [
{
title: { en: `You are functionally testing the newsfeed widget with fixtures!` },
description: { en: 'See test/common/fixtures/plugins/newsfeed/newsfeed_simulation' },
link_text: { en: 'Generic feed-viewer could go here' },
link_url: { en: 'https://feeds.elastic.co' },
languages: null,
badge: null,
image_url: null,
publish_on: '2019-06-21T00:00:00',
expire_on: '2040-01-31T00:00:00',
hash: '39ca7d409c7eb25f4c69a5a6a11309b2f5ced7ca3f9b3a0109517126e0fd91ca',
},
{
title: { en: 'Staging too!' },
description: { en: 'Hello world' },
link_text: { en: 'Generic feed-viewer could go here' },
link_url: { en: 'https://feeds-staging.elastic.co' },
languages: null,
badge: null,
image_url: null,
publish_on: '2019-06-21T00:00:00',
expire_on: '2040-01-31T00:00:00',
hash: 'db445c9443eb50ea2eb15f20edf89cf0f7dac2b058b11cafc2c8c288b6e4ce2a',
},
{
title: { en: 'This item is expired!' },
description: { en: 'This should not show up.' },
link_text: { en: 'Generic feed-viewer could go here' },
link_url: { en: 'https://feeds-staging.elastic.co' },
languages: null,
badge: null,
image_url: null,
publish_on: '2019-06-21T00:00:00',
expire_on: '2019-12-31T00:00:00',
hash: 'db445c9443eb50ea2eb15f20edf89cf0f7dac2b058b11cafc2c8c288b6e4ce2a',
},
],
};
}
}