mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Remove Gainsight from cloud plugin (#172318)
## Summary - Remove gainsight plugin from cloud plugin - add config deprecation in fullstory Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
8f9e11d001
commit
de961a54a7
43 changed files with 2 additions and 3628 deletions
|
@ -29,7 +29,6 @@ snapshots.js
|
|||
/x-pack/plugins/reporting/server/export_types/printable_pdf/server/lib/pdf/assets/**
|
||||
/x-pack/plugins/reporting/server/export_types/printable_pdf_v2/server/lib/pdf/assets/**
|
||||
/x-pack/plugins/cloud_integrations/cloud_full_story/server/assets/**
|
||||
/x-pack/plugins/cloud_integrations/cloud_gain_sight/server/assets/**
|
||||
|
||||
# package overrides
|
||||
/packages/kbn-eslint-config
|
||||
|
|
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
|
@ -39,7 +39,6 @@ packages/analytics/shippers/elastic_v3/browser @elastic/kibana-core
|
|||
packages/analytics/shippers/elastic_v3/common @elastic/kibana-core
|
||||
packages/analytics/shippers/elastic_v3/server @elastic/kibana-core
|
||||
packages/analytics/shippers/fullstory @elastic/kibana-core
|
||||
packages/analytics/shippers/gainsight @elastic/kibana-core
|
||||
packages/kbn-apm-config-loader @elastic/kibana-core @vigneshshanmugam
|
||||
x-pack/plugins/apm_data_access @elastic/obs-knowledge-team @elastic/obs-ux-infra_services-team
|
||||
x-pack/plugins/apm @elastic/obs-ux-infra_services-team
|
||||
|
@ -81,7 +80,6 @@ x-pack/plugins/cloud_integrations/cloud_data_migration @elastic/platform-onboard
|
|||
x-pack/plugins/cloud_defend @elastic/kibana-cloud-security-posture
|
||||
x-pack/plugins/cloud_integrations/cloud_experiments @elastic/kibana-core
|
||||
x-pack/plugins/cloud_integrations/cloud_full_story @elastic/kibana-core
|
||||
x-pack/plugins/cloud_integrations/cloud_gain_sight @elastic/kibana-core
|
||||
x-pack/test/cloud_integration/plugins/saml_provider @elastic/kibana-core
|
||||
x-pack/plugins/cloud_integrations/cloud_links @elastic/kibana-core
|
||||
x-pack/plugins/cloud @elastic/kibana-core
|
||||
|
|
11
NOTICE.txt
11
NOTICE.txt
|
@ -225,11 +225,6 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
---
|
||||
Portions of this code are licensed under the following license:
|
||||
Gainsight PX Agent Wrapper Agent Version: 0.46.0 Installed: 2022-08-25 08:07
|
||||
https://www.gainsight.com/policy/gainsight-px-license-agreement/
|
||||
|
||||
---
|
||||
This code includes a copy of the `normalize-path`
|
||||
https://github.com/jonschlinkert/normalize-path/blob/52c3a95ebebc2d98c1ad7606cbafa7e658656899/index.js
|
||||
|
@ -347,9 +342,3 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
---
|
||||
Copyright (c) 2013 HubSpot, Inc.
|
||||
Released under the MIT license
|
||||
|
||||
https://github.com/HubSpot/vex/blob/master/LICENSE
|
||||
|
||||
|
|
|
@ -502,10 +502,6 @@ The plugin exposes the static DefaultEditorController class to consume.
|
|||
|Integrates with FullStory in order to provide better product analytics, so we can understand how our users make use of Kibana. This plugin should only run on Elastic Cloud.
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/cloud_integrations/cloud_gain_sight/README.md[cloudGainsight]
|
||||
|Integrates with Gainsight in order to provide better product analytics, so we can understand how our users make use of Kibana. This plugin should only run on Elastic Cloud.
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/cloud_integrations/cloud_links/README.md[cloudLinks]
|
||||
|Adds all the links to the Elastic Cloud console.
|
||||
|
||||
|
|
|
@ -158,7 +158,6 @@
|
|||
"@kbn/analytics-shippers-elastic-v3-common": "link:packages/analytics/shippers/elastic_v3/common",
|
||||
"@kbn/analytics-shippers-elastic-v3-server": "link:packages/analytics/shippers/elastic_v3/server",
|
||||
"@kbn/analytics-shippers-fullstory": "link:packages/analytics/shippers/fullstory",
|
||||
"@kbn/analytics-shippers-gainsight": "link:packages/analytics/shippers/gainsight",
|
||||
"@kbn/apm-config-loader": "link:packages/kbn-apm-config-loader",
|
||||
"@kbn/apm-data-access-plugin": "link:x-pack/plugins/apm_data_access",
|
||||
"@kbn/apm-plugin": "link:x-pack/plugins/apm",
|
||||
|
@ -187,7 +186,6 @@
|
|||
"@kbn/cloud-defend-plugin": "link:x-pack/plugins/cloud_defend",
|
||||
"@kbn/cloud-experiments-plugin": "link:x-pack/plugins/cloud_integrations/cloud_experiments",
|
||||
"@kbn/cloud-full-story-plugin": "link:x-pack/plugins/cloud_integrations/cloud_full_story",
|
||||
"@kbn/cloud-gainsight-plugin": "link:x-pack/plugins/cloud_integrations/cloud_gain_sight",
|
||||
"@kbn/cloud-integration-saml-provider-plugin": "link:x-pack/test/cloud_integration/plugins/saml_provider",
|
||||
"@kbn/cloud-links-plugin": "link:x-pack/plugins/cloud_integrations/cloud_links",
|
||||
"@kbn/cloud-plugin": "link:x-pack/plugins/cloud",
|
||||
|
|
|
@ -3,6 +3,5 @@
|
|||
This directory holds the implementation of the _built-in_ shippers provided by the Analytics client. At the moment, the shippers are:
|
||||
|
||||
* [FullStory](./fullstory/README.md)
|
||||
* [Gainsight](./gainsight/README.md)
|
||||
* [Elastic V3 (Browser shipper)](./elastic_v3/browser/README.md)
|
||||
* [Elastic V3 (Server-side shipper)](./elastic_v3/server/README.md)
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
# @kbn/analytics-shippers-gainsight
|
||||
|
||||
Gainsight implementation as a shipper for the `@kbn/analytics-client`.
|
||||
|
||||
## How to use it
|
||||
|
||||
This module is intended to be used **on the browser only**. It does not support server-side events.
|
||||
|
||||
```typescript
|
||||
import { GainsightShipper } from "@kbn/analytics-shippers-gainsight";
|
||||
|
||||
analytics.registerShipper(GainsightShipper, { gainsightOrgId: '12345' })
|
||||
```
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { GainsightShipper } from './src/gainsight_shipper';
|
||||
export type { GainsightSnippetConfig } from './src/load_snippet';
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test/jest_node',
|
||||
rootDir: '../../../../',
|
||||
roots: ['<rootDir>/packages/analytics/shippers/gainsight'],
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"type": "shared-browser",
|
||||
"id": "@kbn/analytics-shippers-gainsight",
|
||||
"owner": "@elastic/kibana-core"
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"name": "@kbn/analytics-shippers-gainsight",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"author": "Kibana Core",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0"
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { GainsightApi } from './types';
|
||||
|
||||
export const gainsightApiMock: GainsightApi = jest.fn();
|
||||
gainsightApiMock.init = true;
|
||||
|
||||
jest.doMock('./load_snippet', () => {
|
||||
return {
|
||||
loadSnippet: () => gainsightApiMock,
|
||||
};
|
||||
});
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { loggerMock } from '@kbn/logging-mocks';
|
||||
import { gainsightApiMock } from './gainsight_shipper.test.mocks';
|
||||
import { GainsightShipper } from './gainsight_shipper';
|
||||
|
||||
describe('gainsightShipper', () => {
|
||||
let gainsightShipper: GainsightShipper;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
gainsightShipper = new GainsightShipper(
|
||||
{
|
||||
gainsightOrgId: 'test-org-id',
|
||||
},
|
||||
{
|
||||
logger: loggerMock.create(),
|
||||
sendTo: 'staging',
|
||||
isDev: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('extendContext', () => {
|
||||
describe('identify', () => {
|
||||
test('calls `identify` when the clusterName is provided', () => {
|
||||
const userId = 'test-user-id';
|
||||
const clusterName = '123654';
|
||||
gainsightShipper.extendContext({ userId, cluster_name: clusterName });
|
||||
expect(gainsightApiMock).toHaveBeenCalledWith('identify', {
|
||||
id: clusterName,
|
||||
userType: 'deployment',
|
||||
});
|
||||
});
|
||||
|
||||
test('calls `identify` again only if the clusterName changes', () => {
|
||||
const userId = 'test-user-id';
|
||||
const clusterName = '123654';
|
||||
gainsightShipper.extendContext({ userId, cluster_name: clusterName });
|
||||
expect(gainsightApiMock).toHaveBeenCalledTimes(2);
|
||||
expect(gainsightApiMock).toHaveBeenCalledWith('identify', {
|
||||
id: clusterName,
|
||||
userType: 'deployment',
|
||||
});
|
||||
expect(gainsightApiMock).toHaveBeenCalledWith('set', 'globalContext', {
|
||||
kibanaUserId: userId,
|
||||
});
|
||||
|
||||
gainsightShipper.extendContext({ userId, cluster_name: clusterName });
|
||||
expect(gainsightApiMock).toHaveBeenCalledTimes(3);
|
||||
|
||||
gainsightShipper.extendContext({ userId, cluster_name: `${clusterName}-1` });
|
||||
expect(gainsightApiMock).toHaveBeenCalledTimes(5); // called again because the user changed
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('optIn', () => {
|
||||
test('should call consent true and restart when isOptIn: true', () => {
|
||||
gainsightShipper.optIn(true);
|
||||
expect(gainsightApiMock).toHaveBeenCalledWith('config', 'enableTag', true);
|
||||
});
|
||||
|
||||
test('should call consent false and shutdown when isOptIn: false', () => {
|
||||
gainsightShipper.optIn(false);
|
||||
expect(gainsightApiMock).toHaveBeenCalledWith('config', 'enableTag', false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reportEvents', () => {
|
||||
test('calls the API once per event in the array with the properties transformed', () => {
|
||||
gainsightShipper.reportEvents([
|
||||
{
|
||||
event_type: 'test-event-1',
|
||||
timestamp: '2020-01-01T00:00:00.000Z',
|
||||
properties: { test: 'test-1' },
|
||||
context: { pageName: 'test-page-1' },
|
||||
},
|
||||
{
|
||||
event_type: 'test-event-2',
|
||||
timestamp: '2020-01-01T00:00:00.000Z',
|
||||
properties: { other_property: 'test-2' },
|
||||
context: { pageName: 'test-page-1' },
|
||||
},
|
||||
]);
|
||||
|
||||
expect(gainsightApiMock).toHaveBeenCalledTimes(2);
|
||||
expect(gainsightApiMock).toHaveBeenCalledWith('track', 'test-event-1', {
|
||||
test: 'test-1',
|
||||
});
|
||||
expect(gainsightApiMock).toHaveBeenCalledWith('track', 'test-event-2', {
|
||||
other_property: 'test-2',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type {
|
||||
AnalyticsClientInitContext,
|
||||
EventContext,
|
||||
Event,
|
||||
IShipper,
|
||||
} from '@kbn/analytics-client';
|
||||
import type { GainsightApi } from './types';
|
||||
import type { GainsightSnippetConfig } from './load_snippet';
|
||||
import { loadSnippet } from './load_snippet';
|
||||
|
||||
/**
|
||||
* gainsight shipper.
|
||||
*/
|
||||
export class GainsightShipper implements IShipper {
|
||||
/** Shipper's unique name */
|
||||
public static shipperName = 'Gainsight';
|
||||
private lastClusterName: string | undefined;
|
||||
private readonly gainsightApi: GainsightApi;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the gainsightShipper.
|
||||
* @param config {@link GainsightSnippetConfig}
|
||||
* @param initContext {@link AnalyticsClientInitContext}
|
||||
*/
|
||||
constructor(
|
||||
config: GainsightSnippetConfig,
|
||||
private readonly initContext: AnalyticsClientInitContext
|
||||
) {
|
||||
const { ...snippetConfig } = config;
|
||||
this.gainsightApi = loadSnippet(snippetConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls track or set on the fields provided in the newContext.
|
||||
* @param newContext The full new context to set {@link EventContext}
|
||||
*/
|
||||
public extendContext(newContext: EventContext): void {
|
||||
this.initContext.logger.debug(`Received context ${JSON.stringify(newContext)}`);
|
||||
|
||||
// gainsight requires different APIs for different type of contexts.
|
||||
const { userId, cluster_name: clusterName } = newContext;
|
||||
|
||||
this.gainsightApi('set', 'globalContext', {
|
||||
kibanaUserId: userId,
|
||||
});
|
||||
|
||||
if (clusterName && clusterName !== this.lastClusterName) {
|
||||
this.initContext.logger.debug(`Calling identify with userId ${userId}`);
|
||||
// We need to call the API for every new userId (restarting the session).
|
||||
this.gainsightApi('identify', {
|
||||
id: clusterName,
|
||||
userType: 'deployment',
|
||||
});
|
||||
this.lastClusterName = clusterName;
|
||||
} else {
|
||||
this.initContext.logger.debug(
|
||||
`Identify has already been called with ${userId} and ${clusterName}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops/restarts the shipping mechanism based on the value of isOptedIn
|
||||
* @param isOptedIn `true` for resume sending events. `false` to stop.
|
||||
*/
|
||||
public optIn(isOptedIn: boolean): void {
|
||||
this.initContext.logger.debug(`Setting gainsight to optIn ${isOptedIn}`);
|
||||
|
||||
if (isOptedIn) {
|
||||
this.gainsightApi('config', 'enableTag', true);
|
||||
} else {
|
||||
this.gainsightApi('config', 'enableTag', false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the event into a valid format and calls `track`.
|
||||
* @param events batched events {@link Event}
|
||||
*/
|
||||
public reportEvents(events: Event[]): void {
|
||||
this.initContext.logger.debug(`Reporting ${events.length} events to gainsight`);
|
||||
events.forEach((event) => {
|
||||
// We only read event.properties and discard the rest because the context is already sent in the other APIs.
|
||||
this.gainsightApi('track', event.event_type, event.properties);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes all internal queues of the shipper.
|
||||
* It doesn't really do anything inside because this shipper doesn't hold any internal queues.
|
||||
*/
|
||||
public async flush() {}
|
||||
|
||||
/**
|
||||
* Shuts down the shipper.
|
||||
* It doesn't really do anything inside because this shipper doesn't hold any internal queues.
|
||||
*/
|
||||
public shutdown() {
|
||||
// No need to do anything here for now.
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { loadSnippet } from './load_snippet';
|
||||
|
||||
describe('loadSnippet', () => {
|
||||
beforeAll(() => {
|
||||
// Define necessary window and document global variables for the tests
|
||||
Object.defineProperty(global, 'window', {
|
||||
writable: true,
|
||||
value: {
|
||||
aptrinsic: {
|
||||
init: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(global, 'document', {
|
||||
writable: true,
|
||||
value: {
|
||||
createElement: jest.fn().mockReturnValue({}),
|
||||
getElementsByTagName: jest
|
||||
.fn()
|
||||
.mockReturnValue([{ parentNode: { insertBefore: jest.fn() } }]),
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(global, 'aptrinsic', {
|
||||
writable: true,
|
||||
value: {
|
||||
init: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the gainsight API', () => {
|
||||
const gainsightApi = loadSnippet({ gainsightOrgId: 'foo' });
|
||||
expect(gainsightApi).toBeDefined();
|
||||
});
|
||||
});
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { GainsightApi } from './types';
|
||||
|
||||
/**
|
||||
* gainsight basic configuration.
|
||||
*/
|
||||
export interface GainsightSnippetConfig {
|
||||
/**
|
||||
* The gainsight account id.
|
||||
*/
|
||||
gainsightOrgId: string;
|
||||
/**
|
||||
* The URL to load the gainsight client from. Falls back to `web-sdk.aptrinsic.com` if not specified.
|
||||
*/
|
||||
scriptUrl?: string;
|
||||
cssFileEndpoint?: string;
|
||||
widgetFileEndpoint?: string;
|
||||
}
|
||||
export function loadSnippet({
|
||||
gainsightOrgId,
|
||||
scriptUrl = 'web-sdk.aptrinsic.com/api/aptrinsic.js',
|
||||
cssFileEndpoint = 'web-sdk.aptrinsic.com/style.css',
|
||||
widgetFileEndpoint = 'web-sdk.aptrinsic.com/widget/aptrinsic-widget.js ',
|
||||
}: GainsightSnippetConfig): GainsightApi {
|
||||
/* eslint-disable no-var,dot-notation,prefer-rest-params,@typescript-eslint/no-unused-expressions */
|
||||
(function (n, t, a, e, co) {
|
||||
var i = 'aptrinsic';
|
||||
// @ts-expect-error
|
||||
(n[i] =
|
||||
// @ts-expect-error
|
||||
n[i] ||
|
||||
function () {
|
||||
// @ts-expect-error
|
||||
(n[i].q = n[i].q || []).push(arguments);
|
||||
}),
|
||||
// @ts-expect-error
|
||||
(n[i].p = e);
|
||||
// @ts-expect-error
|
||||
n[i].c = co;
|
||||
var r = t.createElement('script');
|
||||
(r.async = !1), (r.src = a + '?a=' + e);
|
||||
var c = t.getElementsByTagName('script')[0];
|
||||
// @ts-expect-error
|
||||
c.parentNode.insertBefore(r, c);
|
||||
})(window, document, scriptUrl, gainsightOrgId, {
|
||||
cssFileEndpoint,
|
||||
widgetFileEndpoint,
|
||||
});
|
||||
|
||||
const gainsightApi = window['aptrinsic'];
|
||||
|
||||
if (!gainsightApi || !gainsightApi.init) {
|
||||
throw new Error('Gainsight snippet failed to load. Check browser logs for more information.');
|
||||
}
|
||||
|
||||
return gainsightApi;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Definition of the gainsight API.
|
||||
*/
|
||||
export interface GainsightApi {
|
||||
init?: boolean;
|
||||
(functionId: keyof Mapping, ...options: any): void;
|
||||
}
|
||||
|
||||
interface Mapping {
|
||||
identify: (id: string, userVars?: Record<string, unknown>) => void;
|
||||
track: (event: string, data?: any) => void;
|
||||
set: (event: string, data?: any) => void;
|
||||
reset: () => void;
|
||||
config: (options: any) => void;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
aptrinsic: GainsightApi;
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "target/types",
|
||||
"types": [
|
||||
"jest",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
],
|
||||
"kbn_references": [
|
||||
"@kbn/analytics-client",
|
||||
"@kbn/logging-mocks"
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
]
|
||||
}
|
|
@ -18,7 +18,6 @@ pageLoadAssetSize:
|
|||
cloudDefend: 18697
|
||||
cloudExperiments: 59358
|
||||
cloudFullStory: 18493
|
||||
cloudGainsight: 18710
|
||||
cloudLinks: 55984
|
||||
cloudSecurityPosture: 19109
|
||||
console: 46091
|
||||
|
|
|
@ -63,8 +63,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
'--xpack.cloud_integrations.experiments.launch_darkly.client_id=a_string',
|
||||
'--xpack.cloud_integrations.full_story.enabled=true',
|
||||
'--xpack.cloud_integrations.full_story.org_id=a_string',
|
||||
'--xpack.cloud_integrations.gain_sight.enabled=true',
|
||||
'--xpack.cloud_integrations.gain_sight.org_id=a_string',
|
||||
...findTestPluginPaths(path.resolve(__dirname, 'plugins')),
|
||||
],
|
||||
},
|
||||
|
|
|
@ -239,7 +239,6 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
|
|||
// No PII. Just the list of event types we want to forward to FullStory.
|
||||
'xpack.cloud_integrations.full_story.eventTypesAllowlist (array)',
|
||||
'xpack.cloud_integrations.full_story.pageVarsDebounceTime (duration)',
|
||||
'xpack.cloud_integrations.gain_sight.org_id (any)',
|
||||
'xpack.cloud.id (string)',
|
||||
'xpack.cloud.organization_url (string)',
|
||||
'xpack.cloud.billing_url (string)',
|
||||
|
|
|
@ -72,8 +72,6 @@
|
|||
"@kbn/analytics-shippers-elastic-v3-server/*": ["packages/analytics/shippers/elastic_v3/server/*"],
|
||||
"@kbn/analytics-shippers-fullstory": ["packages/analytics/shippers/fullstory"],
|
||||
"@kbn/analytics-shippers-fullstory/*": ["packages/analytics/shippers/fullstory/*"],
|
||||
"@kbn/analytics-shippers-gainsight": ["packages/analytics/shippers/gainsight"],
|
||||
"@kbn/analytics-shippers-gainsight/*": ["packages/analytics/shippers/gainsight/*"],
|
||||
"@kbn/apm-config-loader": ["packages/kbn-apm-config-loader"],
|
||||
"@kbn/apm-config-loader/*": ["packages/kbn-apm-config-loader/*"],
|
||||
"@kbn/apm-data-access-plugin": ["x-pack/plugins/apm_data_access"],
|
||||
|
@ -156,8 +154,6 @@
|
|||
"@kbn/cloud-experiments-plugin/*": ["x-pack/plugins/cloud_integrations/cloud_experiments/*"],
|
||||
"@kbn/cloud-full-story-plugin": ["x-pack/plugins/cloud_integrations/cloud_full_story"],
|
||||
"@kbn/cloud-full-story-plugin/*": ["x-pack/plugins/cloud_integrations/cloud_full_story/*"],
|
||||
"@kbn/cloud-gainsight-plugin": ["x-pack/plugins/cloud_integrations/cloud_gain_sight"],
|
||||
"@kbn/cloud-gainsight-plugin/*": ["x-pack/plugins/cloud_integrations/cloud_gain_sight/*"],
|
||||
"@kbn/cloud-integration-saml-provider-plugin": ["x-pack/test/cloud_integration/plugins/saml_provider"],
|
||||
"@kbn/cloud-integration-saml-provider-plugin/*": ["x-pack/test/cloud_integration/plugins/saml_provider/*"],
|
||||
"@kbn/cloud-links-plugin": ["x-pack/plugins/cloud_integrations/cloud_links"],
|
||||
|
|
|
@ -64,6 +64,8 @@ export const config: PluginConfigDescriptor<CloudFullStoryConfigType> = {
|
|||
{ path: 'xpack.cloud.full_story.enabled' },
|
||||
{ path: 'xpack.cloud.full_story.org_id' },
|
||||
{ path: 'xpack.cloud.full_story.eventTypesAllowlist' },
|
||||
{ path: 'xpack.cloud_integrations.gain_sight.org_id' },
|
||||
{ path: 'xpack.cloud_integrations.gain_sight.enabled' },
|
||||
],
|
||||
};
|
||||
},
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# Cloud Gainsight
|
||||
|
||||
Integrates with Gainsight in order to provide better product analytics, so we can understand how our users make use of Kibana. This plugin should only run on Elastic Cloud.
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test',
|
||||
rootDir: '../../../../',
|
||||
roots: ['<rootDir>/x-pack/plugins/cloud_integrations/cloud_gain_sight'],
|
||||
coverageDirectory:
|
||||
'<rootDir>/target/kibana-coverage/jest/x-pack/plugins/cloud_integrations/cloud_gain_sight',
|
||||
coverageReporters: ['text', 'html'],
|
||||
collectCoverageFrom: [
|
||||
'<rootDir>/x-pack/plugins/cloud_integrations/cloud_gain_sight/{common,public,server}/**/*.{ts,tsx}',
|
||||
],
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"type": "plugin",
|
||||
"id": "@kbn/cloud-gainsight-plugin",
|
||||
"owner": "@elastic/kibana-core",
|
||||
"description": "When Kibana runs on Elastic Cloud, this plugin registers Gainsight as a shipper for telemetry.",
|
||||
"plugin": {
|
||||
"id": "cloudGainsight",
|
||||
"server": true,
|
||||
"browser": true,
|
||||
"configPath": [
|
||||
"xpack",
|
||||
"cloud_integrations",
|
||||
"gain_sight"
|
||||
],
|
||||
"requiredPlugins": [
|
||||
"cloud"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { PluginInitializerContext } from '@kbn/core/public';
|
||||
import { CloudGainsightPlugin } from './plugin';
|
||||
|
||||
export function plugin(initializerContext: PluginInitializerContext) {
|
||||
return new CloudGainsightPlugin(initializerContext);
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import type { CloudGainsightConfigType } from '../server/config';
|
||||
import { CloudGainsightPlugin } from './plugin';
|
||||
import { cloudMock } from '@kbn/cloud-plugin/public/mocks';
|
||||
|
||||
describe('Cloud Plugin', () => {
|
||||
describe('#setup', () => {
|
||||
describe('setupGainsight', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
const setupPlugin = async ({
|
||||
config = {},
|
||||
isCloudEnabled = true,
|
||||
}: {
|
||||
config?: Partial<CloudGainsightConfigType>;
|
||||
isCloudEnabled?: boolean;
|
||||
}) => {
|
||||
const initContext = coreMock.createPluginInitializerContext(config);
|
||||
|
||||
const plugin = new CloudGainsightPlugin(initContext);
|
||||
|
||||
const coreSetup = coreMock.createSetup();
|
||||
|
||||
const cloud = { ...cloudMock.createSetup(), isCloudEnabled };
|
||||
|
||||
plugin.setup(coreSetup, { cloud });
|
||||
|
||||
// Wait for Gainsight dynamic import to resolve
|
||||
await new Promise((r) => setImmediate(r));
|
||||
|
||||
return { initContext, plugin, coreSetup };
|
||||
};
|
||||
|
||||
test('register the shipper Gainsight with correct args when enabled and org_id are set', async () => {
|
||||
const { coreSetup } = await setupPlugin({
|
||||
config: { org_id: 'foo' },
|
||||
});
|
||||
|
||||
expect(coreSetup.analytics.registerShipper).toHaveBeenCalled();
|
||||
expect(coreSetup.analytics.registerShipper).toHaveBeenCalledWith(expect.anything(), {
|
||||
gainsightOrgId: 'foo',
|
||||
scriptUrl: '/internal/cloud/100/gainsight.js',
|
||||
cssFileEndpoint: '/internal/cloud/100/gainsight.css',
|
||||
widgetFileEndpoint: '/internal/cloud/100/gainsight_widget.js',
|
||||
});
|
||||
});
|
||||
|
||||
it('does not call initializeGainsight when isCloudEnabled=false', async () => {
|
||||
const { coreSetup } = await setupPlugin({
|
||||
config: { org_id: 'foo' },
|
||||
isCloudEnabled: false,
|
||||
});
|
||||
expect(coreSetup.analytics.registerShipper).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not call initializeGainsight when org_id is undefined', async () => {
|
||||
const { coreSetup } = await setupPlugin({ config: {} });
|
||||
expect(coreSetup.analytics.registerShipper).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type {
|
||||
AnalyticsServiceSetup,
|
||||
IBasePath,
|
||||
PluginInitializerContext,
|
||||
CoreSetup,
|
||||
Plugin,
|
||||
} from '@kbn/core/public';
|
||||
import type { CloudSetup } from '@kbn/cloud-plugin/public';
|
||||
|
||||
interface SetupGainsightDeps {
|
||||
analytics: AnalyticsServiceSetup;
|
||||
basePath: IBasePath;
|
||||
}
|
||||
|
||||
interface CloudGainsightConfig {
|
||||
org_id?: string;
|
||||
}
|
||||
|
||||
interface CloudGainsightSetupDeps {
|
||||
cloud: CloudSetup;
|
||||
}
|
||||
|
||||
export class CloudGainsightPlugin implements Plugin {
|
||||
private readonly config: CloudGainsightConfig;
|
||||
|
||||
constructor(private readonly initializerContext: PluginInitializerContext) {
|
||||
this.config = this.initializerContext.config.get<CloudGainsightConfig>();
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup, { cloud }: CloudGainsightSetupDeps) {
|
||||
if (cloud.isCloudEnabled) {
|
||||
this.setupGainsight({ analytics: core.analytics, basePath: core.http.basePath }).catch((e) =>
|
||||
// eslint-disable-next-line no-console
|
||||
console.debug(`Error setting up Gainsight: ${e.toString()}`)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
||||
public stop() {}
|
||||
|
||||
/**
|
||||
* If the right config is provided, register the Gainsight shipper to the analytics client.
|
||||
* @param analytics Core's Analytics service's setup contract.
|
||||
* @param basePath Core's http.basePath helper.
|
||||
* @private
|
||||
*/
|
||||
private async setupGainsight({ analytics, basePath }: SetupGainsightDeps) {
|
||||
const { org_id: gainsightOrgId } = this.config;
|
||||
if (!gainsightOrgId) {
|
||||
return; // do not load any Gainsight code in the browser if not enabled
|
||||
}
|
||||
|
||||
// Keep this import async so that we do not load any Gainsight code into the browser when it is disabled.
|
||||
const { GainsightShipper } = await import('@kbn/analytics-shippers-gainsight');
|
||||
analytics.registerShipper(GainsightShipper, {
|
||||
gainsightOrgId,
|
||||
// Load an Elastic-internally audited script. Ideally, it should be hosted on a CDN.
|
||||
scriptUrl: basePath.prepend(
|
||||
`/internal/cloud/${this.initializerContext.env.packageInfo.buildNum}/gainsight.js`
|
||||
),
|
||||
cssFileEndpoint: basePath.prepend(
|
||||
`/internal/cloud/${this.initializerContext.env.packageInfo.buildNum}/gainsight.css`
|
||||
),
|
||||
widgetFileEndpoint: basePath.prepend(
|
||||
`/internal/cloud/${this.initializerContext.env.packageInfo.buildNum}/gainsight_widget.js`
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { config } from './config';
|
||||
|
||||
describe('xpack.cloud config', () => {
|
||||
describe('gain_sight', () => {
|
||||
it('allows org_id when enabled: false', () => {
|
||||
expect(() => config.schema.validate({ enabled: false, org_id: 'asdf' })).not.toThrow();
|
||||
});
|
||||
|
||||
it('rejects undefined or empty org_id when enabled: true', () => {
|
||||
expect(() => config.schema.validate({ enabled: true })).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[org_id]: expected value of type [string] but got [undefined]"`
|
||||
);
|
||||
expect(() =>
|
||||
config.schema.validate({ enabled: true, org_id: '' })
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[org_id]: value has length [0] but it must have a minimum length of [1]."`
|
||||
);
|
||||
});
|
||||
|
||||
it('accepts org_id when enabled: true', () => {
|
||||
expect(() => config.schema.validate({ enabled: true, org_id: 'asdf' })).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { schema, TypeOf } from '@kbn/config-schema';
|
||||
import { PluginConfigDescriptor } from '@kbn/core/server';
|
||||
|
||||
const configSchema = schema.object({
|
||||
enabled: schema.boolean({ defaultValue: false }),
|
||||
org_id: schema.conditional(
|
||||
schema.siblingRef('enabled'),
|
||||
true,
|
||||
schema.string({ minLength: 1 }),
|
||||
schema.maybe(schema.string())
|
||||
),
|
||||
});
|
||||
|
||||
export type CloudGainsightConfigType = TypeOf<typeof configSchema>;
|
||||
|
||||
export const config: PluginConfigDescriptor<CloudGainsightConfigType> = {
|
||||
exposeToBrowser: {
|
||||
org_id: true,
|
||||
},
|
||||
schema: configSchema,
|
||||
};
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { PluginInitializerContext } from '@kbn/core/server';
|
||||
|
||||
export { config } from './config';
|
||||
|
||||
export async function plugin(initializerContext: PluginInitializerContext) {
|
||||
const { CloudGainsightPlugin } = await import('./plugin');
|
||||
return new CloudGainsightPlugin(initializerContext);
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export const registerGainsightRouteMock = jest.fn();
|
||||
export const registerGainsightStyleRouteMock = jest.fn();
|
||||
export const registerGainsightWidgetRouteMock = jest.fn();
|
||||
|
||||
jest.doMock('./routes', () => ({
|
||||
registerGainsightRoute: registerGainsightRouteMock,
|
||||
registerGainsightStyleRoute: registerGainsightStyleRouteMock,
|
||||
registerGainsightWidgetRoute: registerGainsightWidgetRouteMock,
|
||||
}));
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { coreMock } from '@kbn/core/server/mocks';
|
||||
import { cloudMock } from '@kbn/cloud-plugin/server/mocks';
|
||||
import { registerGainsightRouteMock } from './plugin.test.mock';
|
||||
import { CloudGainsightPlugin } from './plugin';
|
||||
|
||||
describe('Cloud Gainsight plugin', () => {
|
||||
let plugin: CloudGainsightPlugin;
|
||||
beforeEach(() => {
|
||||
registerGainsightRouteMock.mockReset();
|
||||
plugin = new CloudGainsightPlugin(coreMock.createPluginInitializerContext());
|
||||
});
|
||||
|
||||
test('registers route when cloud is enabled', () => {
|
||||
plugin.setup(coreMock.createSetup(), {
|
||||
cloud: { ...cloudMock.createSetup(), isCloudEnabled: true },
|
||||
});
|
||||
expect(registerGainsightRouteMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('does not register the route when cloud is disabled', () => {
|
||||
plugin.setup(coreMock.createSetup(), {
|
||||
cloud: { ...cloudMock.createSetup(), isCloudEnabled: false },
|
||||
});
|
||||
expect(registerGainsightRouteMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { PluginInitializerContext, CoreSetup, Plugin } from '@kbn/core/server';
|
||||
import type { CloudSetup } from '@kbn/cloud-plugin/server';
|
||||
|
||||
import {
|
||||
registerGainsightRoute,
|
||||
registerGainsightStyleRoute,
|
||||
registerGainsightWidgetRoute,
|
||||
} from './routes';
|
||||
|
||||
interface CloudGainsightSetupDeps {
|
||||
cloud: CloudSetup;
|
||||
}
|
||||
|
||||
export class CloudGainsightPlugin implements Plugin {
|
||||
constructor(private readonly initializerContext: PluginInitializerContext) {}
|
||||
|
||||
public setup(core: CoreSetup, { cloud }: CloudGainsightSetupDeps) {
|
||||
if (cloud.isCloudEnabled) {
|
||||
registerGainsightRoute({
|
||||
httpResources: core.http.resources,
|
||||
packageInfo: this.initializerContext.env.packageInfo,
|
||||
});
|
||||
registerGainsightWidgetRoute({
|
||||
httpResources: core.http.resources,
|
||||
packageInfo: this.initializerContext.env.packageInfo,
|
||||
});
|
||||
registerGainsightStyleRoute({
|
||||
httpResources: core.http.resources,
|
||||
packageInfo: this.initializerContext.env.packageInfo,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
||||
public stop() {}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
jest.mock('fs/promises');
|
||||
import { renderGainsightLibraryFactory, GAINSIGHT_LIBRARY_PATH } from './gainsight';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
const fsMock = fs as jest.Mocked<typeof fs>;
|
||||
|
||||
describe('renderGainsightLibraryFactory', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
fsMock.readFile.mockResolvedValue(Buffer.from('fake fs src'));
|
||||
});
|
||||
afterAll(() => jest.restoreAllMocks());
|
||||
|
||||
it('successfully returns file contents', async () => {
|
||||
const render = renderGainsightLibraryFactory();
|
||||
|
||||
const { body } = await render();
|
||||
expect(fsMock.readFile).toHaveBeenCalledWith(GAINSIGHT_LIBRARY_PATH);
|
||||
expect(body.toString()).toEqual('fake fs src');
|
||||
});
|
||||
|
||||
it('only reads from file system once callback is invoked', async () => {
|
||||
const render = renderGainsightLibraryFactory();
|
||||
expect(fsMock.readFile).not.toHaveBeenCalled();
|
||||
await render();
|
||||
expect(fsMock.readFile).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not read from filesystem on subsequent calls', async () => {
|
||||
const render = renderGainsightLibraryFactory();
|
||||
await render();
|
||||
expect(fsMock.readFile).toHaveBeenCalledTimes(1);
|
||||
await render();
|
||||
expect(fsMock.readFile).toHaveBeenCalledTimes(1);
|
||||
await render();
|
||||
expect(fsMock.readFile).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('returns max-age cache-control in dist', async () => {
|
||||
const render = renderGainsightLibraryFactory(true);
|
||||
const { headers } = await render();
|
||||
expect(headers).toEqual({
|
||||
'cache-control': 'max-age=31536000',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns must-revalidate cache-control and sha1 etag in dev', async () => {
|
||||
const render = renderGainsightLibraryFactory(false);
|
||||
const { headers } = await render();
|
||||
expect(headers).toEqual({
|
||||
'cache-control': 'must-revalidate',
|
||||
etag: '1e02f94b45750ba9284c111d31ae7e59c13b8e6e',
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs/promises';
|
||||
import { createHash } from 'crypto';
|
||||
import { once } from 'lodash';
|
||||
import { HttpResources, HttpResponseOptions, PackageInfo } from '@kbn/core/server';
|
||||
|
||||
const MINUTE = 60;
|
||||
const HOUR = 60 * MINUTE;
|
||||
const DAY = 24 * HOUR;
|
||||
|
||||
/** @internal exported for testing */
|
||||
export const GAINSIGHT_LIBRARY_PATH = path.join(__dirname, '..', 'assets', 'gainsight_library.js');
|
||||
export const GAINSIGHT_WIDGET_PATH = path.join(__dirname, '..', 'assets', 'gainsight_widget.js');
|
||||
export const GAINSIGHT_STYLE_PATH = path.join(__dirname, '..', 'assets', 'gainsight_style.css');
|
||||
|
||||
/** @internal exported for testing */
|
||||
export const renderGainsightLibraryFactory = (dist = true, filePath = GAINSIGHT_LIBRARY_PATH) =>
|
||||
once(
|
||||
async (): Promise<{
|
||||
body: Buffer;
|
||||
headers: HttpResponseOptions['headers'];
|
||||
}> => {
|
||||
const srcBuffer = await fs.readFile(filePath);
|
||||
|
||||
return {
|
||||
body: srcBuffer,
|
||||
// In dist mode, return a long max-age, otherwise use etag + must-revalidate
|
||||
headers: dist
|
||||
? { 'cache-control': `max-age=${DAY * 365}` }
|
||||
: { 'cache-control': 'must-revalidate', etag: calculateHash(srcBuffer) },
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
function calculateHash(srcBuffer: Buffer) {
|
||||
const hash = createHash('sha1');
|
||||
hash.update(srcBuffer);
|
||||
return hash.digest('hex');
|
||||
}
|
||||
|
||||
export const registerGainsightRoute = ({
|
||||
httpResources,
|
||||
packageInfo,
|
||||
}: {
|
||||
httpResources: HttpResources;
|
||||
packageInfo: Readonly<PackageInfo>;
|
||||
}) => {
|
||||
const renderGainsightLibrary = renderGainsightLibraryFactory(
|
||||
packageInfo.dist,
|
||||
GAINSIGHT_LIBRARY_PATH
|
||||
);
|
||||
|
||||
/**
|
||||
* Register a custom JS endpoint in order to achieve best caching possible with `max-age` similar to plugin bundles.
|
||||
*/
|
||||
httpResources.register(
|
||||
{
|
||||
// Use the build number in the URL path to leverage max-age caching on production builds
|
||||
path: `/internal/cloud/${packageInfo.buildNum}/gainsight.js`,
|
||||
validate: false,
|
||||
options: {
|
||||
authRequired: false,
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
try {
|
||||
return res.renderJs(await renderGainsightLibrary());
|
||||
} catch (e) {
|
||||
return res.customError({
|
||||
body: `Could not load Gainsight library from disk due to error: ${e.toString()}`,
|
||||
statusCode: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const registerGainsightStyleRoute = ({
|
||||
httpResources,
|
||||
packageInfo,
|
||||
}: {
|
||||
httpResources: HttpResources;
|
||||
packageInfo: Readonly<PackageInfo>;
|
||||
}) => {
|
||||
const renderGainsightLibrary = renderGainsightLibraryFactory(
|
||||
packageInfo.dist,
|
||||
GAINSIGHT_STYLE_PATH
|
||||
);
|
||||
|
||||
/**
|
||||
* Register a custom endpoint in order to achieve best caching possible with `max-age` similar to plugin bundles.
|
||||
*/
|
||||
httpResources.register(
|
||||
{
|
||||
// Use the build number in the URL path to leverage max-age caching on production builds
|
||||
path: `/internal/cloud/${packageInfo.buildNum}/gainsight.css`,
|
||||
validate: false,
|
||||
options: {
|
||||
authRequired: false,
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
try {
|
||||
return res.renderCss(await renderGainsightLibrary());
|
||||
} catch (e) {
|
||||
return res.customError({
|
||||
body: `Could not load Gainsight library from disk due to error: ${e.toString()}`,
|
||||
statusCode: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const registerGainsightWidgetRoute = ({
|
||||
httpResources,
|
||||
packageInfo,
|
||||
}: {
|
||||
httpResources: HttpResources;
|
||||
packageInfo: Readonly<PackageInfo>;
|
||||
}) => {
|
||||
const renderGainsightLibrary = renderGainsightLibraryFactory(
|
||||
packageInfo.dist,
|
||||
GAINSIGHT_WIDGET_PATH
|
||||
);
|
||||
|
||||
/**
|
||||
* Register a custom JS endpoint in order to achieve best caching possible with `max-age` similar to plugin bundles.
|
||||
*/
|
||||
httpResources.register(
|
||||
{
|
||||
// Use the build number in the URL path to leverage max-age caching on production builds
|
||||
path: `/internal/cloud/${packageInfo.buildNum}/gainsight_widget.js`,
|
||||
validate: false,
|
||||
options: {
|
||||
authRequired: false,
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
try {
|
||||
return res.renderJs(await renderGainsightLibrary());
|
||||
} catch (e) {
|
||||
return res.customError({
|
||||
body: `Could not load Gainsight library from disk due to error: ${e.toString()}`,
|
||||
statusCode: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export {
|
||||
registerGainsightRoute,
|
||||
registerGainsightStyleRoute,
|
||||
registerGainsightWidgetRoute,
|
||||
} from './gainsight';
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "target/types",
|
||||
},
|
||||
"include": [
|
||||
".storybook/**/*",
|
||||
"common/**/*",
|
||||
"public/**/*",
|
||||
"server/**/*",
|
||||
"../../../typings/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"server/assets/*.js",
|
||||
"target/**/*",
|
||||
],
|
||||
"kbn_references": [
|
||||
"@kbn/core",
|
||||
"@kbn/cloud-plugin",
|
||||
"@kbn/config-schema",
|
||||
"@kbn/analytics-shippers-gainsight",
|
||||
]
|
||||
}
|
|
@ -3200,10 +3200,6 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/analytics-shippers-gainsight@link:packages/analytics/shippers/gainsight":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/analytics@link:packages/kbn-analytics":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
@ -3368,10 +3364,6 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/cloud-gainsight-plugin@link:x-pack/plugins/cloud_integrations/cloud_gain_sight":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/cloud-integration-saml-provider-plugin@link:x-pack/test/cloud_integration/plugins/saml_provider":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue