Skip to content

Commit a65abc0

Browse files
ashikmeerankuttyflash1293
authored andcommitted
Convert vis_type_vega to Typescript (elastic#68915)
1 parent a725e84 commit a65abc0

File tree

14 files changed

+511
-158
lines changed

14 files changed

+511
-158
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@
138138
"@kbn/babel-preset": "1.0.0",
139139
"@kbn/config-schema": "1.0.0",
140140
"@kbn/i18n": "1.0.0",
141-
"@kbn/telemetry-tools": "1.0.0",
142141
"@kbn/interpreter": "1.0.0",
143142
"@kbn/pm": "1.0.0",
143+
"@kbn/telemetry-tools": "1.0.0",
144144
"@kbn/test-subj-selector": "0.2.1",
145145
"@kbn/ui-framework": "1.0.0",
146146
"@kbn/ui-shared-deps": "1.0.0",
@@ -340,6 +340,7 @@
340340
"@types/hapi-auth-cookie": "^9.1.0",
341341
"@types/has-ansi": "^3.0.0",
342342
"@types/history": "^4.7.3",
343+
"@types/hjson": "^2.4.2",
343344
"@types/hoek": "^4.1.3",
344345
"@types/inert": "^5.1.2",
345346
"@types/jest": "^25.2.3",

renovate.json5

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,14 @@
426426
'@types/history',
427427
],
428428
},
429+
{
430+
groupSlug: 'hjson',
431+
groupName: 'hjson related packages',
432+
packageNames: [
433+
'hjson',
434+
'@types/hjson',
435+
],
436+
},
429437
{
430438
groupSlug: 'inquirer',
431439
groupName: 'inquirer related packages',

src/plugins/maps_legacy/public/map/service_settings.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,5 @@ export interface IServiceSettings {
4848
getEMSHotLink(layer: FileLayer): Promise<string>;
4949
getTMSServices(): Promise<TmsLayer[]>;
5050
getFileLayers(): Promise<FileLayer[]>;
51+
getUrlForRegionLayer(layer: FileLayer): Promise<string>;
5152
}

src/plugins/vis_type_vega/public/components/vega_vis_editor.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import React, { useCallback } from 'react';
2121
import { EuiCodeEditor } from '@elastic/eui';
2222
import compactStringify from 'json-stringify-pretty-compact';
23-
// @ts-ignore
2423
import hjson from 'hjson';
2524
import 'brace/mode/hjson';
2625
import { i18n } from '@kbn/i18n';
@@ -45,7 +44,11 @@ const hjsonStringifyOptions = {
4544
keepWsc: true,
4645
};
4746

48-
function format(value: string, stringify: typeof compactStringify, options?: any) {
47+
function format(
48+
value: string,
49+
stringify: typeof hjson.stringify | typeof compactStringify,
50+
options?: any
51+
) {
4952
try {
5053
const spec = hjson.parse(value, { legacyRoot: false, keepWsc: true });
5154
return stringify(spec, options);

src/plugins/vis_type_vega/public/data_model/ems_file_parser.js renamed to src/plugins/vis_type_vega/public/data_model/ems_file_parser.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,28 @@
1818
*/
1919

2020
import { i18n } from '@kbn/i18n';
21+
// @ts-ignore
2122
import { bypassExternalUrlCheck } from '../vega_view/vega_base_view';
23+
import { IServiceSettings, FileLayer } from '../../../maps_legacy/public';
24+
import { Data, UrlObject, Requests } from './types';
2225

2326
/**
2427
* This class processes all Vega spec customizations,
2528
* converting url object parameters into query results.
2629
*/
2730
export class EmsFileParser {
28-
constructor(serviceSettings) {
31+
_serviceSettings: IServiceSettings;
32+
_fileLayersP?: Promise<FileLayer[]>;
33+
34+
constructor(serviceSettings: IServiceSettings) {
2935
this._serviceSettings = serviceSettings;
3036
}
3137

3238
// noinspection JSMethodCanBeStatic
3339
/**
3440
* Update request object, expanding any context-aware keywords
3541
*/
36-
parseUrl(obj, url) {
42+
parseUrl(obj: Data, url: UrlObject) {
3743
if (typeof url.name !== 'string') {
3844
throw new Error(
3945
i18n.translate('visTypeVega.emsFileParser.missingNameOfFileErrorMessage', {
@@ -59,13 +65,13 @@ export class EmsFileParser {
5965
* @param {object[]} requests each object is generated by parseUrl()
6066
* @returns {Promise<void>}
6167
*/
62-
async populateData(requests) {
68+
async populateData(requests: Requests[]) {
6369
if (requests.length === 0) return;
6470

6571
const layers = await this._fileLayersP;
6672

6773
for (const { obj, name } of requests) {
68-
const foundLayer = layers.find((v) => v.name === name);
74+
const foundLayer = layers?.find((v) => v.name === name);
6975
if (!foundLayer) {
7076
throw new Error(
7177
i18n.translate('visTypeVega.emsFileParser.emsFileNameDoesNotExistErrorMessage', {

src/plugins/vis_type_vega/public/data_model/es_query_parser.js renamed to src/plugins/vis_type_vega/public/data_model/es_query_parser.ts

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,38 @@
1919

2020
import moment from 'moment';
2121
import { i18n } from '@kbn/i18n';
22-
import { isPlainObject, cloneDeep } from 'lodash';
22+
import { cloneDeep, isPlainObject } from 'lodash';
23+
import { SearchParams } from 'elasticsearch';
24+
import { TimeCache } from './time_cache';
25+
import { SearchAPI } from './search_api';
26+
import { Opts, Type, Data, UrlObject, Bool, Requests, Query, ContextVarsObject } from './types';
2327

24-
const TIMEFILTER = '%timefilter%';
25-
const AUTOINTERVAL = '%autointerval%';
26-
const MUST_CLAUSE = '%dashboard_context-must_clause%';
27-
const FILTER_CLAUSE = '%dashboard_context-filter_clause%';
28-
const MUST_NOT_CLAUSE = '%dashboard_context-must_not_clause%';
28+
const TIMEFILTER: string = '%timefilter%';
29+
const AUTOINTERVAL: string = '%autointerval%';
30+
const MUST_CLAUSE: string = '%dashboard_context-must_clause%';
31+
const MUST_NOT_CLAUSE: string = '%dashboard_context-must_not_clause%';
32+
const FILTER_CLAUSE: string = '%dashboard_context-filter_clause%';
2933

3034
// These values may appear in the 'url': { ... } object
31-
const LEGACY_CONTEXT = '%context_query%';
32-
const CONTEXT = '%context%';
33-
const TIMEFIELD = '%timefield%';
35+
const LEGACY_CONTEXT: string = '%context_query%';
36+
const CONTEXT: string = '%context%';
37+
const TIMEFIELD: string = '%timefield%';
3438

3539
/**
3640
* This class parses ES requests specified in the data.url objects.
3741
*/
3842
export class EsQueryParser {
39-
constructor(timeCache, searchAPI, filters, onWarning) {
43+
_timeCache: TimeCache;
44+
_searchAPI: SearchAPI;
45+
_filters: Bool;
46+
_onWarning: (...args: string[]) => void;
47+
48+
constructor(
49+
timeCache: TimeCache,
50+
searchAPI: SearchAPI,
51+
filters: Bool,
52+
onWarning: (...args: string[]) => void
53+
) {
4054
this._timeCache = timeCache;
4155
this._searchAPI = searchAPI;
4256
this._filters = filters;
@@ -47,7 +61,7 @@ export class EsQueryParser {
4761
/**
4862
* Update request object, expanding any context-aware keywords
4963
*/
50-
parseUrl(dataObject, url) {
64+
parseUrl(dataObject: Data, url: UrlObject) {
5165
let body = url.body;
5266
let context = url[CONTEXT];
5367
delete url[CONTEXT];
@@ -167,13 +181,13 @@ export class EsQueryParser {
167181
// Use dashboard context
168182
const newQuery = cloneDeep(this._filters);
169183
if (timefield) {
170-
newQuery.bool.must.push(body.query);
184+
newQuery.bool!.must!.push(body.query);
171185
}
172186
body.query = newQuery;
173187
}
174188
}
175189

176-
this._injectContextVars(body.aggs, false);
190+
this._injectContextVars(body.aggs!, false);
177191
return { dataObject, url };
178192
}
179193

@@ -182,8 +196,8 @@ export class EsQueryParser {
182196
* @param {object[]} requests each object is generated by parseUrl()
183197
* @returns {Promise<void>}
184198
*/
185-
async populateData(requests) {
186-
const esSearches = requests.map((r) => r.url);
199+
async populateData(requests: Requests[]) {
200+
const esSearches = requests.map((r: Requests) => r.url);
187201
const data$ = this._searchAPI.search(esSearches);
188202

189203
const results = await data$.toPromise();
@@ -198,7 +212,7 @@ export class EsQueryParser {
198212
* @param {*} obj
199213
* @param {boolean} isQuery - if true, the `obj` belongs to the req's query portion
200214
*/
201-
_injectContextVars(obj, isQuery) {
215+
_injectContextVars(obj: Query | SearchParams['body']['aggs'], isQuery: boolean) {
202216
if (obj && typeof obj === 'object') {
203217
if (Array.isArray(obj)) {
204218
// For arrays, replace MUST_CLAUSE and MUST_NOT_CLAUSE string elements
@@ -239,7 +253,7 @@ export class EsQueryParser {
239253
}
240254
} else {
241255
for (const prop of Object.keys(obj)) {
242-
const subObj = obj[prop];
256+
const subObj = (obj as ContextVarsObject)[prop];
243257
if (!subObj || typeof obj !== 'object') continue;
244258

245259
// replace "interval": { "%autointerval%": true|integer } with
@@ -260,7 +274,9 @@ export class EsQueryParser {
260274
);
261275
}
262276
const bounds = this._timeCache.getTimeBounds();
263-
obj.interval = EsQueryParser._roundInterval((bounds.max - bounds.min) / size);
277+
(obj as ContextVarsObject).interval = EsQueryParser._roundInterval(
278+
(bounds.max - bounds.min) / size
279+
);
264280
continue;
265281
}
266282

@@ -269,7 +285,7 @@ export class EsQueryParser {
269285
case 'min':
270286
case 'max':
271287
// Replace {"%timefilter%": "min|max", ...} object with a timestamp
272-
obj[prop] = this._getTimeBound(subObj, subObj[TIMEFILTER]);
288+
(obj as ContextVarsObject)[prop] = this._getTimeBound(subObj, subObj[TIMEFILTER]);
273289
continue;
274290
case true:
275291
// Replace {"%timefilter%": true, ...} object with the "range" object
@@ -302,7 +318,7 @@ export class EsQueryParser {
302318
* @param {object} obj
303319
* @return {object}
304320
*/
305-
_createRangeFilter(obj) {
321+
_createRangeFilter(obj: Opts) {
306322
obj.gte = moment(this._getTimeBound(obj, 'min')).toISOString();
307323
obj.lte = moment(this._getTimeBound(obj, 'max')).toISOString();
308324
obj.format = 'strict_date_optional_time';
@@ -320,9 +336,9 @@ export class EsQueryParser {
320336
* @param {'min'|'max'} type
321337
* @returns {*}
322338
*/
323-
_getTimeBound(opts, type) {
339+
_getTimeBound(opts: Opts, type: Type): number {
324340
const bounds = this._timeCache.getTimeBounds();
325-
let result = bounds[type];
341+
let result = bounds[type]?.valueOf() || 0;
326342

327343
if (opts.shift) {
328344
const shift = opts.shift;
@@ -380,7 +396,7 @@ export class EsQueryParser {
380396
* @param interval (ms)
381397
* @returns {string}
382398
*/
383-
static _roundInterval(interval) {
399+
static _roundInterval(interval: number): string {
384400
switch (true) {
385401
case interval <= 500: // <= 0.5s
386402
return '100ms';

src/plugins/vis_type_vega/public/data_model/time_cache.js renamed to src/plugins/vis_type_vega/public/data_model/time_cache.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,47 @@
1717
* under the License.
1818
*/
1919

20+
import { TimefilterContract } from '../../../data/public';
21+
import { TimeRange } from '../../../data/common';
22+
import { CacheBounds } from './types';
23+
2024
/**
2125
* Optimization caching - always return the same value if queried within this time
2226
* @type {number}
2327
*/
24-
const AlwaysCacheMaxAge = 40;
28+
29+
const AlwaysCacheMaxAge: number = 40;
2530

2631
/**
2732
* This class caches timefilter's bounds to minimize number of server requests
2833
*/
2934
export class TimeCache {
30-
constructor(timefilter, maxAge) {
35+
_timefilter: TimefilterContract;
36+
_maxAge: number;
37+
_cachedBounds?: CacheBounds;
38+
_cacheTS: number;
39+
_timeRange?: TimeRange;
40+
41+
constructor(timefilter: TimefilterContract, maxAge: number) {
3142
this._timefilter = timefilter;
3243
this._maxAge = maxAge;
33-
this._cachedBounds = null;
3444
this._cacheTS = 0;
3545
}
3646

3747
// Simplifies unit testing
3848
// noinspection JSMethodCanBeStatic
39-
_now() {
49+
_now(): number {
4050
return Date.now();
4151
}
4252

4353
/**
4454
* Get cached time range values
4555
* @returns {{min: number, max: number}}
4656
*/
47-
getTimeBounds() {
57+
getTimeBounds(): CacheBounds {
4858
const ts = this._now();
4959

50-
let bounds;
60+
let bounds: CacheBounds | null = null;
5161
if (this._cachedBounds) {
5262
const diff = ts - this._cacheTS;
5363

@@ -76,7 +86,7 @@ export class TimeCache {
7686
return this._cachedBounds;
7787
}
7888

79-
setTimeRange(timeRange) {
89+
setTimeRange(timeRange: TimeRange): void {
8090
this._timeRange = timeRange;
8191
}
8292

@@ -85,11 +95,11 @@ export class TimeCache {
8595
* @returns {{min: number, max: number}}
8696
* @private
8797
*/
88-
_getBounds() {
89-
const bounds = this._timefilter.calculateBounds(this._timeRange);
98+
_getBounds(): CacheBounds {
99+
const bounds = this._timefilter.calculateBounds(this._timeRange!);
90100
return {
91-
min: bounds.min.valueOf(),
92-
max: bounds.max.valueOf(),
101+
min: bounds.min!.valueOf(),
102+
max: bounds.max!.valueOf(),
93103
};
94104
}
95105
}

0 commit comments

Comments
 (0)