TypeScript project references for APM (#90049) (#91354)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Dario Gieselaar <dario.gieselaar@elastic.co>

Co-authored-by: Nathan L Smith <nathan.smith@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Dario Gieselaar 2021-02-15 07:13:06 +01:00 committed by GitHub
parent 15bb592c02
commit 79d0956687
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 189 additions and 141 deletions

View file

@ -28,10 +28,6 @@ export const PROJECTS = [
name: 'apm/ftr_e2e',
disableTypeCheck: true,
}),
new Project(resolve(REPO_ROOT, 'x-pack/plugins/apm/scripts/tsconfig.json'), {
name: 'apm/scripts',
disableTypeCheck: true,
}),
// NOTE: using glob.sync rather than glob-all or globby
// because it takes less than 10 ms, while the other modules

View file

@ -57,6 +57,7 @@
{ "path": "./src/plugins/index_pattern_management/tsconfig.json" },
{ "path": "./x-pack/plugins/actions/tsconfig.json" },
{ "path": "./x-pack/plugins/alerts/tsconfig.json" },
{ "path": "./x-pack/plugins/apm/tsconfig.json" },
{ "path": "./x-pack/plugins/beats_management/tsconfig.json" },
{ "path": "./x-pack/plugins/canvas/tsconfig.json" },
{ "path": "./x-pack/plugins/cloud/tsconfig.json" },
@ -106,10 +107,10 @@
{ "path": "./x-pack/plugins/runtime_fields/tsconfig.json" },
{ "path": "./x-pack/plugins/index_management/tsconfig.json" },
{ "path": "./x-pack/plugins/watcher/tsconfig.json" },
{ "path": "./x-pack/plugins/rollup/tsconfig.json"},
{ "path": "./x-pack/plugins/remote_clusters/tsconfig.json"},
{ "path": "./x-pack/plugins/cross_cluster_replication/tsconfig.json"},
{ "path": "./x-pack/plugins/index_lifecycle_management/tsconfig.json"},
{ "path": "./x-pack/plugins/uptime/tsconfig.json" },
{ "path": "./x-pack/plugins/rollup/tsconfig.json" },
{ "path": "./x-pack/plugins/remote_clusters/tsconfig.json" },
{ "path": "./x-pack/plugins/cross_cluster_replication/tsconfig.json" },
{ "path": "./x-pack/plugins/index_lifecycle_management/tsconfig.json" },
{ "path": "./x-pack/plugins/uptime/tsconfig.json" }
]
}

View file

@ -7,27 +7,34 @@
import { i18n } from '@kbn/i18n';
import cytoscape from 'cytoscape';
import {
AGENT_NAME,
SERVICE_ENVIRONMENT,
SERVICE_NAME,
SPAN_DESTINATION_SERVICE_RESOURCE,
SPAN_SUBTYPE,
SPAN_TYPE,
} from './elasticsearch_fieldnames';
import { ServiceAnomalyStats } from './anomaly_detection';
// These should be imported, but until TypeScript 4.2 we're inlining them here.
// All instances of "agent.name", "service.name", "service.environment", "span.type",
// "span.subtype", and "span.destination.service.resource" need to be changed
// back to using the constants.
// See https://github.com/microsoft/TypeScript/issues/37888
//
// import {
// AGENT_NAME,
// SERVICE_ENVIRONMENT,
// SERVICE_NAME,
// SPAN_DESTINATION_SERVICE_RESOURCE,
// SPAN_SUBTYPE,
// SPAN_TYPE,
// } from './elasticsearch_fieldnames';
export interface ServiceConnectionNode extends cytoscape.NodeDataDefinition {
[SERVICE_NAME]: string;
[SERVICE_ENVIRONMENT]: string | null;
[AGENT_NAME]: string;
'service.name': string;
'service.environment': string | null;
'agent.name': string;
serviceAnomalyStats?: ServiceAnomalyStats;
label?: string;
}
export interface ExternalConnectionNode extends cytoscape.NodeDataDefinition {
[SPAN_DESTINATION_SERVICE_RESOURCE]: string;
[SPAN_TYPE]: string;
[SPAN_SUBTYPE]: string;
'span.destination.service.resource': string;
'span.type': string;
'span.subtype': string;
label?: string;
}

View file

@ -25,19 +25,14 @@
],
"server": true,
"ui": true,
"configPath": [
"xpack",
"apm"
],
"extraPublicDirs": [
"public/style/variables"
],
"configPath": ["xpack", "apm"],
"extraPublicDirs": ["public/style/variables"],
"requiredBundles": [
"home",
"kibanaReact",
"kibanaUtils",
"observability",
"home",
"maps",
"ml"
"ml",
"observability"
]
}

View file

@ -5,11 +5,21 @@
* 2.0.
*/
import React from 'react';
import { EuiButtonEmpty, EuiTitle } from '@elastic/eui';
import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common';
import { EuiButtonEmpty, EuiButtonEmptyProps, EuiTitle } from '@elastic/eui';
import React, { FunctionComponent } from 'react';
import { StyledComponent } from 'styled-components';
import {
euiStyled,
EuiTheme,
} from '../../../../../../../../../src/plugins/kibana_react/common';
const Button = euiStyled(EuiButtonEmpty).attrs(() => ({
// The return type of this component needs to be specified because the inferred
// return type depends on types that are not exported from EUI. You get a TS4023
// error if the return type is not specified.
const Button: StyledComponent<
FunctionComponent<EuiButtonEmptyProps>,
EuiTheme
> = euiStyled(EuiButtonEmpty).attrs(() => ({
contentProps: {
className: 'alignLeft',
},

View file

@ -27,7 +27,7 @@ export const CytoscapeContext = createContext<cytoscape.Core | undefined>(
undefined
);
interface CytoscapeProps {
export interface CytoscapeProps {
children?: ReactNode;
elements: cytoscape.ElementDefinition[];
height: number;

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import React, { ComponentProps } from 'react';
import { SyncBadge } from './SyncBadge';
import React from 'react';
import { SyncBadge, SyncBadgeProps } from './SyncBadge';
export default {
title: 'app/TransactionDetails/SyncBadge',
@ -18,7 +18,7 @@ export default {
},
};
export function Example({ sync }: ComponentProps<typeof SyncBadge>) {
export function Example({ sync }: SyncBadgeProps) {
return <SyncBadge sync={sync} />;
}
Example.args = { sync: true } as ComponentProps<typeof SyncBadge>;
Example.args = { sync: true } as SyncBadgeProps;

View file

@ -16,7 +16,7 @@ const SpanBadge = euiStyled(EuiBadge)`
margin-right: ${px(units.quarter)};
`;
interface SyncBadgeProps {
export interface SyncBadgeProps {
/**
* Is the request synchronous? True will show blocking, false will show async.
*/

View file

@ -25,7 +25,7 @@ import { getDateRange } from './helpers';
import { resolveUrlParams } from './resolve_url_params';
import { IUrlParams } from './types';
interface TimeRange {
export interface TimeRange {
rangeFrom: string;
rangeTo: string;
}

View file

@ -9,7 +9,7 @@ import { useMemo } from 'react';
import { useParams } from 'react-router-dom';
import { useFetcher } from './use_fetcher';
import { useUrlParams } from '../context/url_params_context/use_url_params';
import { getThrouputChartSelector } from '../selectors/throuput_chart_selectors';
import { getThroughputChartSelector } from '../selectors/throughput_chart_selectors';
import { useTheme } from './use_theme';
import { useApmServiceContext } from '../context/apm_service/use_apm_service_context';
@ -45,7 +45,7 @@ export function useTransactionThroughputChartsFetcher() {
);
const memoizedData = useMemo(
() => getThrouputChartSelector({ throuputChart: data, theme }),
() => getThroughputChartSelector({ throughputChart: data, theme }),
[data, theme]
);

View file

@ -15,7 +15,7 @@ import { APIReturnType } from '../services/rest/createCallApmApi';
export type LatencyChartsResponse = APIReturnType<'GET /api/apm/services/{serviceName}/transactions/charts/latency'>;
interface LatencyChartData {
export interface LatencyChartData {
latencyTimeseries: Array<APMChartSpec<Coordinate>>;
mlJobId?: string;
anomalyTimeseries?: { boundaries: APMChartSpec[]; scores: APMChartSpec };

View file

@ -7,9 +7,9 @@
import { EuiTheme } from '../../../../../src/plugins/kibana_react/common';
import {
getThrouputChartSelector,
ThrouputChartsResponse,
} from './throuput_chart_selectors';
getThroughputChartSelector,
ThroughputChartsResponse,
} from './throughput_chart_selectors';
const theme = {
eui: {
@ -30,26 +30,26 @@ const throughputData = {
{ key: 'HTTP 4xx', avg: 1, dataPoints: [{ x: 1, y: 2 }] },
{ key: 'HTTP 5xx', avg: 1, dataPoints: [{ x: 1, y: 2 }] },
],
} as ThrouputChartsResponse;
} as ThroughputChartsResponse;
describe('getThrouputChartSelector', () => {
describe('getThroughputChartSelector', () => {
it('returns default values when data is undefined', () => {
const throughputTimeseries = getThrouputChartSelector({ theme });
const throughputTimeseries = getThroughputChartSelector({ theme });
expect(throughputTimeseries).toEqual({ throughputTimeseries: [] });
});
it('returns default values when timeseries is empty', () => {
const throughputTimeseries = getThrouputChartSelector({
const throughputTimeseries = getThroughputChartSelector({
theme,
throuputChart: { throughputTimeseries: [] },
throughputChart: { throughputTimeseries: [] },
});
expect(throughputTimeseries).toEqual({ throughputTimeseries: [] });
});
it('return throughput time series', () => {
const throughputTimeseries = getThrouputChartSelector({
const throughputTimeseries = getThroughputChartSelector({
theme,
throuputChart: throughputData,
throughputChart: throughputData,
});
expect(throughputTimeseries).toEqual({

View file

@ -12,36 +12,36 @@ import { TimeSeries } from '../../typings/timeseries';
import { APIReturnType } from '../services/rest/createCallApmApi';
import { httpStatusCodeToColor } from '../utils/httpStatusCodeToColor';
export type ThrouputChartsResponse = APIReturnType<'GET /api/apm/services/{serviceName}/transactions/charts/throughput'>;
export type ThroughputChartsResponse = APIReturnType<'GET /api/apm/services/{serviceName}/transactions/charts/throughput'>;
interface ThroughputChart {
export interface ThroughputChart {
throughputTimeseries: TimeSeries[];
}
export function getThrouputChartSelector({
export function getThroughputChartSelector({
theme,
throuputChart,
throughputChart,
}: {
theme: EuiTheme;
throuputChart?: ThrouputChartsResponse;
throughputChart?: ThroughputChartsResponse;
}): ThroughputChart {
if (!throuputChart) {
if (!throughputChart) {
return { throughputTimeseries: [] };
}
return {
throughputTimeseries: getThroughputTimeseries({ throuputChart, theme }),
throughputTimeseries: getThroughputTimeseries({ throughputChart, theme }),
};
}
function getThroughputTimeseries({
throuputChart,
throughputChart,
theme,
}: {
theme: EuiTheme;
throuputChart: ThrouputChartsResponse;
throughputChart: ThroughputChartsResponse;
}) {
const { throughputTimeseries } = throuputChart;
const { throughputTimeseries } = throughputChart;
const bucketKeys = throughputTimeseries.map(({ key }) => key);
const getColor = getColorByKey(bucketKeys, theme);

View file

@ -118,7 +118,7 @@ _Note: Run the following commands from `kibana/`._
### Typescript
```
yarn tsc --noEmit --project x-pack/tsconfig.json --skipLibCheck
yarn tsc --noEmit --project x-pack/plugins/apm/tsconfig.json --skipLibCheck
```
### Prettier

View file

@ -14,7 +14,7 @@ const { resolve } = require('path');
const cwd = resolve(__dirname, '../../../..');
const execaOpts = { cwd, stderr: 'pipe' };
const execaOpts = { cwd, stderr: 'inherit' };
const tasks = new Listr(
[
@ -36,18 +36,10 @@ const tasks = new Listr(
{
title: 'Typescript',
task: () =>
execa('node', [resolve(__dirname, 'optimize-tsconfig.js')]).then(() =>
execa(
require.resolve('typescript/bin/tsc'),
[
'--project',
resolve(__dirname, '../../../tsconfig.json'),
'--pretty',
'--noEmit',
'--skipLibCheck',
],
execaOpts
)
execa(
require.resolve('typescript/bin/tsc'),
['--project', resolve(__dirname, '../tsconfig.json'), '--pretty'],
execaOpts
),
},
{
@ -61,10 +53,9 @@ const tasks = new Listr(
tasks.run().catch((error) => {
// from src/dev/typescript/exec_in_projects.ts
process.exitCode = 1;
const errors = error.errors || [error];
for (const e of errors) {
process.stderr.write(e.stdout);
process.stderr.write(e.stderr || e.stdout);
}
});

View file

@ -30,17 +30,25 @@ export function getEsClient({
auth,
});
return {
...client,
async search<TDocument, TSearchRequest extends ESSearchRequest>(
request: TSearchRequest
) {
const response = await client.search(request as any);
async function search<
TDocument = unknown,
TSearchRequest extends ESSearchRequest = ESSearchRequest
>(request: TSearchRequest) {
const response = await client.search<TDocument>(request);
return {
...response,
body: response.body as ESSearchResponse<TDocument, TSearchRequest>,
};
},
return {
...response,
body: (response.body as unknown) as ESSearchResponse<
TDocument,
TSearchRequest
>,
};
}
// @ts-expect-error
client.search = search;
return (client as unknown) as Omit<Client, 'search'> & {
search: typeof search;
};
}

View file

@ -1,13 +0,0 @@
{
"extends": "../../../../tsconfig.base.json",
"include": [
"./**/*",
"../observability"
],
"exclude": [],
"compilerOptions": {
"types": [
"node"
]
}
}

View file

@ -83,7 +83,7 @@ async function uploadData() {
apmAgentConfigurationIndex: '.apm-agent-configuration',
},
search: (body) => {
return unwrapEsResponse(client.search<any>(body));
return unwrapEsResponse(client.search<any>(body as any));
},
indicesStats: (body) => {
return unwrapEsResponse(client.indices.stats<any>(body));

View file

@ -6,29 +6,29 @@
*/
import { ValuesType } from 'utility-types';
import { unwrapEsResponse } from '../../../../../../observability/server';
import { APMError } from '../../../../../typings/es_schemas/ui/apm_error';
import {
ElasticsearchClient,
KibanaRequest,
} from '../../../../../../../../src/core/server';
import { ProcessorEvent } from '../../../../../common/processor_event';
import {
ESSearchRequest,
ESSearchResponse,
} from '../../../../../../../typings/elasticsearch';
import { ApmIndicesConfig } from '../../../settings/apm_indices/get_apm_indices';
import { addFilterToExcludeLegacyData } from './add_filter_to_exclude_legacy_data';
import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
import { Span } from '../../../../../typings/es_schemas/ui/span';
import { unwrapEsResponse } from '../../../../../../observability/server';
import { ProcessorEvent } from '../../../../../common/processor_event';
import { APMError } from '../../../../../typings/es_schemas/ui/apm_error';
import { Metric } from '../../../../../typings/es_schemas/ui/metric';
import { unpackProcessorEvents } from './unpack_processor_events';
import { Span } from '../../../../../typings/es_schemas/ui/span';
import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
import { ApmIndicesConfig } from '../../../settings/apm_indices/get_apm_indices';
import {
callAsyncWithDebug,
getDebugTitle,
getDebugBody,
getDebugTitle,
} from '../call_async_with_debug';
import { cancelEsRequestOnAbort } from '../cancel_es_request_on_abort';
import { addFilterToExcludeLegacyData } from './add_filter_to_exclude_legacy_data';
import { unpackProcessorEvents } from './unpack_processor_events';
export type APMEventESSearchRequest = Omit<ESSearchRequest, 'index'> & {
apm: {
@ -36,11 +36,13 @@ export type APMEventESSearchRequest = Omit<ESSearchRequest, 'index'> & {
};
};
// These keys shoul all be `ProcessorEvent.x`, but until TypeScript 4.2 we're inlining them here.
// See https://github.com/microsoft/TypeScript/issues/37888
type TypeOfProcessorEvent<T extends ProcessorEvent> = {
[ProcessorEvent.error]: APMError;
[ProcessorEvent.transaction]: Transaction;
[ProcessorEvent.span]: Span;
[ProcessorEvent.metric]: Metric;
error: APMError;
transaction: Transaction;
span: Span;
metric: Metric;
}[T];
type ESSearchRequestOf<TParams extends APMEventESSearchRequest> = Omit<

View file

@ -13,7 +13,7 @@ import {
import { APMRequestHandlerContext } from '../../routes/typings';
import { withApmSpan } from '../../utils/with_apm_span';
interface IndexPatternTitleAndFields {
export interface IndexPatternTitleAndFields {
title: string;
fields: FieldDescriptor[];
}

View file

@ -33,7 +33,7 @@ type ServiceMetadataDetailsRaw = Pick<
'service' | 'agent' | 'host' | 'container' | 'kubernetes' | 'cloud'
>;
interface ServiceMetadataDetails {
export interface ServiceMetadataDetails {
service?: {
versions?: string[];
runtime?: {

View file

@ -27,7 +27,7 @@ type ServiceMetadataIconsRaw = Pick<
'kubernetes' | 'cloud' | 'container' | 'agent'
>;
interface ServiceMetadataIcons {
export interface ServiceMetadataIcons {
agentName?: string;
containerType?: ContainerType;
cloudProvider?: string;

View file

@ -6,29 +6,34 @@
*/
import * as t from 'io-ts';
import {
SERVICE_NAME,
SERVICE_ENVIRONMENT,
TRANSACTION_NAME,
TRANSACTION_TYPE,
} from '../../../../common/elasticsearch_fieldnames';
// These should be imported, but until TypeScript 4.2 we're inlining them here.
// All instances of "service.name", "service.environment", "transaction.name",
// and "transaction.type" need to be changed back to using the constants.
// See https://github.com/microsoft/TypeScript/issues/37888
// import {
// SERVICE_NAME,
// SERVICE_ENVIRONMENT,
// TRANSACTION_NAME,
// TRANSACTION_TYPE,
// } from '../../../../common/elasticsearch_fieldnames';
export interface CustomLinkES {
id?: string;
'@timestamp'?: number;
label: string;
url: string;
[SERVICE_NAME]?: string[];
[SERVICE_ENVIRONMENT]?: string[];
[TRANSACTION_NAME]?: string[];
[TRANSACTION_TYPE]?: string[];
'service.name'?: string[];
'service.environment'?: string[];
'transaction.name'?: string[];
'transaction.type'?: string[];
}
export const filterOptionsRt = t.partial({
[SERVICE_NAME]: t.string,
[SERVICE_ENVIRONMENT]: t.string,
[TRANSACTION_NAME]: t.string,
[TRANSACTION_TYPE]: t.string,
'service.name': t.string,
'service.environment': t.string,
'transaction.name': t.string,
'transaction.type': t.string,
});
export const payloadRt = t.intersection([

View file

@ -20,7 +20,7 @@ import { Setup, SetupTimeRange } from '../helpers/setup_request';
import { PromiseValueType } from '../../../typings/common';
import { withApmSpan } from '../../utils/with_apm_span';
interface ErrorsPerTransaction {
export interface ErrorsPerTransaction {
[transactionId: string]: number;
}

View file

@ -213,7 +213,7 @@ export function transactionGroupsFetcher(
});
}
interface TransactionGroup {
export interface TransactionGroup {
key: string | Record<'service.name' | 'transaction.name', string>;
serviceName: string;
transactionName: string;

View file

@ -0,0 +1,45 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"outDir": "./target/types",
"emitDeclarationOnly": true,
"declaration": true,
"declarationMap": true
},
"include": [
"../../typings/**/*",
"common/**/*",
"public/**/*",
"scripts/**/*",
"server/**/*",
"typings/**/*",
// have to declare *.json explicitly due to https://github.com/microsoft/TypeScript/issues/25636
"public/**/*.json",
"server/**/*.json"
],
"references": [
{ "path": "../../../src/core/tsconfig.json" },
{ "path": "../../../src/plugins/apm_oss/tsconfig.json" },
{ "path": "../../../src/plugins/data/tsconfig.json" },
{ "path": "../../../src/plugins/embeddable/tsconfig.json" },
{ "path": "../../../src/plugins/home/tsconfig.json" },
{ "path": "../../../src/plugins/index_pattern_management/tsconfig.json" },
{ "path": "../../../src/plugins/kibana_react/tsconfig.json" },
{ "path": "../../../src/plugins/kibana_utils/tsconfig.json" },
{ "path": "../../../src/plugins/usage_collection/tsconfig.json" },
{ "path": "../actions/tsconfig.json" },
{ "path": "../alerts/tsconfig.json" },
{ "path": "../cloud/tsconfig.json" },
{ "path": "../features/tsconfig.json" },
{ "path": "../infra/tsconfig.json" },
{ "path": "../licensing/tsconfig.json" },
{ "path": "../maps/tsconfig.json" },
{ "path": "../ml/tsconfig.json" },
{ "path": "../observability/tsconfig.json" },
{ "path": "../reporting/tsconfig.json" },
{ "path": "../security/tsconfig.json" },
{ "path": "../task_manager/tsconfig.json" },
{ "path": "../triggers_actions_ui/tsconfig.json" }
]
}

View file

@ -40,6 +40,7 @@
{ "path": "../../src/plugins/usage_collection/tsconfig.json" },
{ "path": "../plugins/actions/tsconfig.json" },
{ "path": "../plugins/alerts/tsconfig.json" },
{ "path": "../plugins/apm/tsconfig.json" },
{ "path": "../plugins/banners/tsconfig.json" },
{ "path": "../plugins/beats_management/tsconfig.json" },
{ "path": "../plugins/cloud/tsconfig.json" },

View file

@ -4,7 +4,6 @@
"mocks.ts",
"typings/**/*",
"tasks/**/*",
"plugins/apm/**/*",
"plugins/case/**/*",
"plugins/lists/**/*",
"plugins/logstash/**/*",
@ -62,6 +61,7 @@
{ "path": "../src/plugins/usage_collection/tsconfig.json" },
{ "path": "./plugins/actions/tsconfig.json" },
{ "path": "./plugins/alerts/tsconfig.json" },
{ "path": "./plugins/apm/tsconfig.json" },
{ "path": "./plugins/beats_management/tsconfig.json" },
{ "path": "./plugins/canvas/tsconfig.json" },
{ "path": "./plugins/cloud/tsconfig.json" },