Skip to content

Commit 10ae4ee

Browse files
authored
[Discover] Add long numerals support (opensearch-project#5592)
* Fix the usage of `pegjs` in tasks Signed-off-by: Miki <miki@amazon.com> * [Discover] Add long numerals support * Add long numerals support to Discover tabular view, document view, inspector, hash-url, and share * Use a fork of `numeral-js` that supports long numerals * Patch `rison` to correctly serialize BigInts * Replace the uses of `withLongNumerals` with `withLongNumeralsSupport` to match the rest of the codebase and mark `withLongNumerals` for deprecation * Add `withLongNumeralsSupport` as an option to `code/public/http/fetch` * Add long numerals support to `UiSettingsClient` * Add long numerals support to `core/server/http/router` response handler * Add long numerals support to `RangeFilter` and `FilterBar` * Add long numerals support to `kuery/ast` * Introduce `OPENSEARCH_SEARCH_WITH_LONG_NUMERALS_STRATEGY` in `core/plugins/data/search` * Remove `ng-non-bindable` leftovers Signed-off-by: Miki <miki@amazon.com> --------- Signed-off-by: Miki <miki@amazon.com>
1 parent 09b64a4 commit 10ae4ee

File tree

55 files changed

+457
-247
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+457
-247
lines changed

.eslintignore

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ target
1818
# plugin overrides
1919
/src/core/lib/osd_internal_native_observable
2020
/src/legacy/plugin_discovery/plugin_pack/__tests__/fixtures/plugins/broken
21-
/src/plugins/data/common/opensearch_query/kuery/ast/_generated_/**
22-
/src/plugins/vis_type_timeline/public/_generated_/**
21+
/src/plugins/**/_generated_/**
2322

2423
# package overrides
2524
/packages/opensearch-eslint-config-opensearch-dashboards

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
88

99
### Deprecations
1010

11+
- Rename `withLongNumerals` to `withLongNumeralsSupport` in `HttpFetchOptions` [#5592](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5592)
12+
1113
### 🛡 Security
1214

1315
- [WS-2021-0638] Bump mocha from `7.2.0` to `10.1.0` ([#2711](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2711))
@@ -23,6 +25,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
2325
- [Workspace] Add core workspace service module to enable the implementation of workspace features within OSD plugins ([#5092](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5092))
2426
- [Workspace] Setup workspace skeleton and implement basic CRUD API ([#5075](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5075))
2527
- [Decouple] Add new cross compatibility check core service which export functionality for plugins to verify if their OpenSearch plugin counterpart is installed on the cluster or has incompatible version to configure the plugin behavior([#4710](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4710))
28+
- [Discover] Add long numerals support [#5592](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5592)
2629
- [Discover] Display inner properties in the left navigation bar [#5429](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5429)
2730
- [Chrome] Introduce registerCollapsibleNavHeader to allow plugins to customize the rendering of nav menu header ([#5244](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5244))
2831
- [Custom Branding] Relative URL should be allowed for logos ([#5572](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5572))

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@
130130
"@elastic/datemath": "5.0.3",
131131
"@elastic/eui": "npm:@opensearch-project/oui@1.4.0",
132132
"@elastic/good": "^9.0.1-kibana3",
133-
"@elastic/numeral": "^2.5.0",
133+
"@elastic/numeral": "npm:@amoo-miki/numeral@2.6.0",
134134
"@elastic/request-crypto": "2.0.0",
135135
"@elastic/safer-lodash-set": "0.0.0",
136136
"@hapi/accept": "^5.0.2",

packages/osd-std/src/json.ts

+1
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ export const parse = (
285285
if (
286286
numeralsAreNumbers &&
287287
typeof val === 'number' &&
288+
isFinite(val) &&
288289
(val < Number.MAX_SAFE_INTEGER || val > Number.MAX_SAFE_INTEGER)
289290
) {
290291
numeralsAreNumbers = false;

packages/osd-ui-shared-deps/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"dependencies": {
1212
"@elastic/charts": "31.1.0",
1313
"@elastic/eui": "npm:@opensearch-project/oui@1.4.0",
14-
"@elastic/numeral": "^2.5.0",
14+
"@elastic/numeral": "npm:@amoo-miki/numeral@2.6.0",
1515
"@opensearch/datemath": "5.0.3",
1616
"@osd/i18n": "1.0.0",
1717
"@osd/monaco": "1.0.0",
@@ -52,3 +52,4 @@
5252
"webpack": "npm:@amoo-miki/webpack@4.46.0-rc.2"
5353
}
5454
}
55+

scripts/postinstall.js

+13
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ const run = async () => {
7171
},
7272
])
7373
);
74+
promises.push(
75+
patchFile('node_modules/rison-node/js/rison.js', [
76+
{
77+
from: 'return Number(s)',
78+
to:
79+
'return isFinite(s) && (s > Number.MAX_SAFE_INTEGER || s < Number.MIN_SAFE_INTEGER) ? BigInt(s) : Number(s)',
80+
},
81+
{
82+
from: 's = {',
83+
to: 's = {\n bigint: x => x.toString(),',
84+
},
85+
])
86+
);
7487

7588
await Promise.all(promises);
7689
};

src/core/public/http/fetch.test.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,9 @@ describe('Fetch', () => {
839839
},
840840
});
841841

842-
await expect(fetchInstance.fetch('/my/path', { withLongNumerals: true })).resolves.toEqual({
842+
await expect(
843+
fetchInstance.fetch('/my/path', { withLongNumeralsSupport: true })
844+
).resolves.toEqual({
843845
'long-max': longPositive,
844846
'long-min': longNegative,
845847
});
@@ -854,7 +856,9 @@ describe('Fetch', () => {
854856
},
855857
});
856858

857-
await expect(fetchInstance.fetch('/my/path', { withLongNumerals: true })).resolves.toEqual({
859+
await expect(
860+
fetchInstance.fetch('/my/path', { withLongNumeralsSupport: true })
861+
).resolves.toEqual({
858862
'long-max': longPositive,
859863
'long-min': longNegative,
860864
});

src/core/public/http/fetch.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,20 @@ export class Fetch {
190190
if (NDJSON_CONTENT.test(contentType)) {
191191
body = await response.blob();
192192
} else if (JSON_CONTENT.test(contentType)) {
193-
body = fetchOptions.withLongNumerals ? parse(await response.text()) : await response.json();
193+
// ToDo: [3.x] Remove withLongNumerals
194+
body =
195+
fetchOptions.withLongNumeralsSupport || fetchOptions.withLongNumerals
196+
? parse(await response.text())
197+
: await response.json();
194198
} else {
195199
const text = await response.text();
196200

197201
try {
198-
body = fetchOptions.withLongNumerals ? parse(text) : JSON.parse(text);
202+
// ToDo: [3.x] Remove withLongNumerals
203+
body =
204+
fetchOptions.withLongNumeralsSupport || fetchOptions.withLongNumerals
205+
? parse(text)
206+
: JSON.parse(text);
199207
} catch (err) {
200208
body = text;
201209
}

src/core/public/http/types.ts

+3
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ export interface HttpFetchOptions extends HttpRequestInit {
262262
* When `true`, if the response has a JSON mime type, the {@link HttpResponse} will use an alternate JSON parser
263263
* that converts long numerals to BigInts. Defaults to `false`.
264264
*/
265+
withLongNumeralsSupport?: boolean;
266+
267+
/** @deprecated use {@link withLongNumeralsSupport} instead */
265268
withLongNumerals?: boolean;
266269
}
267270

src/core/public/ui_settings/__snapshots__/ui_settings_client.test.ts.snap

+24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/core/public/ui_settings/ui_settings_client.test.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@ import { UiSettingsClient } from './ui_settings_client';
3636
let done$: Subject<unknown>;
3737

3838
function setup(options: { defaults?: any; initialSettings?: any } = {}) {
39-
const { defaults = { dateFormat: { value: 'Browser' } }, initialSettings = {} } = options;
39+
const {
40+
defaults = {
41+
dateFormat: { value: 'Browser' },
42+
aLongNumeral: { value: `${BigInt(Number.MAX_SAFE_INTEGER) + 11n}`, type: 'number' },
43+
},
44+
initialSettings = {},
45+
} = options;
4046

4147
const batchSet = jest.fn(() => ({
4248
settings: {},
@@ -62,6 +68,7 @@ describe('#get', () => {
6268
it('gives access to uiSettings values', () => {
6369
const { client } = setup();
6470
expect(client.get('dateFormat')).toMatchSnapshot();
71+
expect(client.get('aLongNumeral')).toBe(BigInt(Number.MAX_SAFE_INTEGER) + 11n);
6572
});
6673

6774
it('supports the default value overload', () => {
@@ -82,13 +89,19 @@ describe('#get', () => {
8289
const { client } = setup();
8390
// if you are hitting this error, then a test is setting this client value globally and not unsetting it!
8491
expect(client.isDefault('dateFormat')).toBe(true);
92+
expect(client.isDefault('aLongNumeral')).toBe(true);
8593

8694
const defaultDateFormat = client.get('dateFormat');
95+
const defaultLongNumeral = client.get('aLongNumeral');
8796

8897
expect(client.get('dateFormat', 'xyz')).toBe('xyz');
98+
expect(client.get('aLongNumeral', 1n)).toBe(1n);
99+
89100
// shouldn't change other usages
90101
expect(client.get('dateFormat')).toBe(defaultDateFormat);
91102
expect(client.get('dataFormat', defaultDateFormat)).toBe(defaultDateFormat);
103+
expect(client.get('aLongNumeral')).toBe(defaultLongNumeral);
104+
expect(client.get('aLongNumeral', defaultLongNumeral)).toBe(defaultLongNumeral);
92105
});
93106

94107
it("throws on unknown properties that don't have a value yet.", () => {

src/core/public/ui_settings/ui_settings_client.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ You can use \`IUiSettingsClient.get("${key}", defaultValue)\`, which will just r
9797
return JSON.parse(value);
9898
}
9999

100-
if (type === 'number') {
101-
return parseFloat(value);
102-
}
103-
104-
return value;
100+
return type === 'number' && typeof value !== 'bigint'
101+
? isFinite(value) && (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER)
102+
? BigInt(value)
103+
: parseFloat(value)
104+
: value;
105105
}
106106

107107
get$<T = any>(key: string, defaultOverride?: T) {

src/core/server/http/router/response.ts

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ export interface HttpResponseOptions {
8787
body?: HttpResponsePayload;
8888
/** HTTP Headers with additional information about response */
8989
headers?: ResponseHeaders;
90+
/** Indicates if alternate serialization should be employed */
91+
withLongNumeralsSupport?: boolean;
9092
}
9193

9294
/**

src/core/server/http/router/response_adapter.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
import typeDetect from 'type-detect';
3636
import Boom from '@hapi/boom';
3737
import * as stream from 'stream';
38+
import { stringify } from '@osd/std';
3839

3940
import {
4041
HttpResponsePayload,
@@ -108,9 +109,18 @@ export class HapiResponseAdapter {
108109
opensearchDashboardsResponse: OpenSearchDashboardsResponse<HttpResponsePayload>
109110
) {
110111
const response = this.responseToolkit
111-
.response(opensearchDashboardsResponse.payload)
112+
.response(
113+
opensearchDashboardsResponse.options.withLongNumeralsSupport
114+
? stringify(opensearchDashboardsResponse.payload)
115+
: opensearchDashboardsResponse.payload
116+
)
112117
.code(opensearchDashboardsResponse.status);
113118
setHeaders(response, opensearchDashboardsResponse.options.headers);
119+
if (opensearchDashboardsResponse.options.withLongNumeralsSupport) {
120+
setHeaders(response, {
121+
'content-type': 'application/json',
122+
});
123+
}
114124
return response;
115125
}
116126

src/plugins/console/public/lib/opensearch/opensearch.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export async function send(
5757
body: data,
5858
prependBasePath: true,
5959
asResponse: true,
60-
withLongNumerals: true,
60+
withLongNumeralsSupport: true,
6161
});
6262
}
6363

src/plugins/data/common/field_formats/content_types/html_content_type.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export const setup = (
7272
};
7373

7474
const wrap: HtmlContextTypeConvert = (value, options) => {
75-
return `<span ng-non-bindable>${recurse(value, options)}</span>`;
75+
return `<span>${recurse(value, options)}</span>`;
7676
};
7777

7878
return wrap;

src/plugins/data/common/field_formats/converters/color.test.ts

+15-15
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ describe('Color Format', () => {
4848
jest.fn()
4949
);
5050

51-
expect(colorer.convert(99, HTML_CONTEXT_TYPE)).toBe('<span ng-non-bindable>99</span>');
51+
expect(colorer.convert(99, HTML_CONTEXT_TYPE)).toBe('<span>99</span>');
5252
expect(colorer.convert(100, HTML_CONTEXT_TYPE)).toBe(
53-
'<span ng-non-bindable><span style="color: blue;background-color: yellow;">100</span></span>'
53+
'<span><span style="color: blue;background-color: yellow;">100</span></span>'
5454
);
5555
expect(colorer.convert(150, HTML_CONTEXT_TYPE)).toBe(
56-
'<span ng-non-bindable><span style="color: blue;background-color: yellow;">150</span></span>'
56+
'<span><span style="color: blue;background-color: yellow;">150</span></span>'
5757
);
58-
expect(colorer.convert(151, HTML_CONTEXT_TYPE)).toBe('<span ng-non-bindable>151</span>');
58+
expect(colorer.convert(151, HTML_CONTEXT_TYPE)).toBe('<span>151</span>');
5959
});
6060

6161
test('should not convert invalid ranges', () => {
@@ -73,7 +73,7 @@ describe('Color Format', () => {
7373
jest.fn()
7474
);
7575

76-
expect(colorer.convert(99, HTML_CONTEXT_TYPE)).toBe('<span ng-non-bindable>99</span>');
76+
expect(colorer.convert(99, HTML_CONTEXT_TYPE)).toBe('<span>99</span>');
7777
});
7878
});
7979

@@ -94,26 +94,26 @@ describe('Color Format', () => {
9494
);
9595
const converter = colorer.getConverterFor(HTML_CONTEXT_TYPE) as Function;
9696

97-
expect(converter('B', HTML_CONTEXT_TYPE)).toBe('<span ng-non-bindable>B</span>');
97+
expect(converter('B', HTML_CONTEXT_TYPE)).toBe('<span>B</span>');
9898
expect(converter('AAA', HTML_CONTEXT_TYPE)).toBe(
99-
'<span ng-non-bindable><span style="color: blue;background-color: yellow;">AAA</span></span>'
99+
'<span><span style="color: blue;background-color: yellow;">AAA</span></span>'
100100
);
101101
expect(converter('AB', HTML_CONTEXT_TYPE)).toBe(
102-
'<span ng-non-bindable><span style="color: blue;background-color: yellow;">AB</span></span>'
102+
'<span><span style="color: blue;background-color: yellow;">AB</span></span>'
103103
);
104-
expect(converter('a', HTML_CONTEXT_TYPE)).toBe('<span ng-non-bindable>a</span>');
104+
expect(converter('a', HTML_CONTEXT_TYPE)).toBe('<span>a</span>');
105105

106-
expect(converter('B', HTML_CONTEXT_TYPE)).toBe('<span ng-non-bindable>B</span>');
106+
expect(converter('B', HTML_CONTEXT_TYPE)).toBe('<span>B</span>');
107107
expect(converter('AAA', HTML_CONTEXT_TYPE)).toBe(
108-
'<span ng-non-bindable><span style="color: blue;background-color: yellow;">AAA</span></span>'
108+
'<span><span style="color: blue;background-color: yellow;">AAA</span></span>'
109109
);
110110
expect(converter('AB', HTML_CONTEXT_TYPE)).toBe(
111-
'<span ng-non-bindable><span style="color: blue;background-color: yellow;">AB</span></span>'
111+
'<span><span style="color: blue;background-color: yellow;">AB</span></span>'
112112
);
113113
expect(converter('AB <', HTML_CONTEXT_TYPE)).toBe(
114-
'<span ng-non-bindable><span style="color: blue;background-color: yellow;">AB &lt;</span></span>'
114+
'<span><span style="color: blue;background-color: yellow;">AB &lt;</span></span>'
115115
);
116-
expect(converter('a', HTML_CONTEXT_TYPE)).toBe('<span ng-non-bindable>a</span>');
116+
expect(converter('a', HTML_CONTEXT_TYPE)).toBe('<span>a</span>');
117117
});
118118

119119
test('returns original value (escaped) when regex is invalid', () => {
@@ -132,7 +132,7 @@ describe('Color Format', () => {
132132
);
133133
const converter = colorer.getConverterFor(HTML_CONTEXT_TYPE) as Function;
134134

135-
expect(converter('<', HTML_CONTEXT_TYPE)).toBe('<span ng-non-bindable>&lt;</span>');
135+
expect(converter('<', HTML_CONTEXT_TYPE)).toBe('<span>&lt;</span>');
136136
});
137137
});
138138
});

0 commit comments

Comments
 (0)