Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.x] Add aliased vega-lite v5 dependency and bundle from source #3151

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,11 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

* [MD] Add design documents of multiple data source feature [#2538](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2538)
* Corrected README and help command of osd-plugin-helpers ([#2810](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2810))

### 🛠 Maintenance

- Remove `github-checks-reporter`, an unused dependency ([#3126](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3126))
- Add `vega-lite` v5 dependency aliased as `vega-lite-next` ([#3076](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3076))

### 🪛 Refactoring
* [MD] Refactor data source error handling ([#2661](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2661))
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@
"vega": "^5.17.3",
"vega-interpreter": "npm:@amoo-miki/[email protected]",
"vega-lite": "^4.16.8",
"vega-lite-next": "npm:vega-lite@^5.6.0",
"vega-schema-url-parser": "^2.1.0",
"vega-tooltip": "^0.24.2",
"vinyl-fs": "^3.0.3",
Expand Down
16 changes: 8 additions & 8 deletions packages/osd-babel-preset/common_preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,27 @@ const plugins = [
require.resolve('babel-plugin-add-module-exports'),

// The class properties proposal was merged with the private fields proposal
// into the "class fields" proposal. Babel doesn't support this combined
// proposal yet, which includes private field, so this transform is
// TECHNICALLY stage 2, but for all intents and purposes it's stage 3
//
// into the "class fields" proposal which is stage 3.
// See https://github.com/babel/proposals/issues/12 for progress
require.resolve('@babel/plugin-proposal-class-properties'),

// Optional Chaining proposal is stage 3 (https://github.com/tc39/proposal-optional-chaining)
// Optional Chaining proposal is stage 4 (https://github.com/tc39/proposal-optional-chaining)
// Need this since we are using TypeScript 3.7+
require.resolve('@babel/plugin-proposal-optional-chaining'),
// Nullish coalescing proposal is stage 3 (https://github.com/tc39/proposal-nullish-coalescing)
// Nullish coalescing proposal is stage 4 (https://github.com/tc39/proposal-nullish-coalescing)
// Need this since we are using TypeScript 3.7+
require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'),

// Proposal is on stage 4 (https://github.com/tc39/proposal-export-ns-from)
// Proposal is merged into ECMA-262 (https://github.com/tc39/proposal-export-ns-from)
// Need this since we are using TypeScript 3.8+
require.resolve('@babel/plugin-proposal-export-namespace-from'),

// Proposal is on stage 4 (https://github.com/tc39/proposal-export-ns-from)
// Proposal is merged into ECMA-262 (https://github.com/tc39/proposal-export-ns-from)
// Need this since we are using TypeScript 3.9+
require.resolve('@babel/plugin-proposal-private-methods'),

// Proposal is on stage 4 (https://github.com/tc39/proposal-logical-assignment)
require.resolve('@babel/plugin-proposal-logical-assignment-operators'),
];

module.exports = {
Expand Down
1 change: 1 addition & 0 deletions packages/osd-babel-preset/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"dependencies": {
"@babel/plugin-proposal-class-properties": "^7.16.5",
"@babel/plugin-proposal-export-namespace-from": "^7.16.5",
"@babel/plugin-proposal-logical-assignment-operators": "^7.16.5",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.5",
"@babel/plugin-proposal-optional-chaining": "^7.16.5",
"@babel/plugin-proposal-private-methods": "^7.16.5",
Expand Down
4 changes: 3 additions & 1 deletion packages/osd-optimizer/src/worker/webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker:
},
{
test: /\.(js|tsx?)$/,
exclude: /node_modules/,
// vega-lite and some of its dependencies don't have es5 builds
// so we need to build from source and transpile for webpack v4
exclude: /[\/\\]node_modules[\/\\](?!vega-(lite-next|label|functions)[\/\\])/,
Comment on lines +207 to +209
Copy link
Collaborator

@AMoo-Miki AMoo-Miki Jan 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we checked that this doesn't interfere with the original vega-lite? Maybe by pulling in an extension that uses the original one?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I can confirm it doesn't in a couple ways - when I was creating #3076 from this diff, I accidentally validated that. The jest tests do their own direct import of vega-lite and I had initially missed changing them, because they all still worked. And without the lite-next part of that regex correctly ensures that vega-lite will be ignored.

use: {
loader: 'babel-loader',
options: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jest.mock('../services');

jest.mock('../lib/vega', () => ({
vega: jest.requireActual('vega'),
vegaLite: jest.requireActual('vega-lite'),
vegaLite: jest.requireActual('vega-lite-next/src'),
}));

describe(`VegaParser.parseAsync`, () => {
Expand Down Expand Up @@ -245,11 +245,15 @@ describe('VegaParser.parseSchema', () => {

test(
'should not warn on current vega-lite version',
check('https://vega.github.io/schema/vega-lite/v5.json', true, 0)
);
test(
'should not warn on older vega-lite version',
check('https://vega.github.io/schema/vega-lite/v4.json', true, 0)
);
test(
'should warn on vega-lite version too new to be supported',
check('https://vega.github.io/schema/vega-lite/v5.json', true, 1)
check('https://vega.github.io/schema/vega-lite/v6.json', true, 1)
);
});

Expand Down
64 changes: 32 additions & 32 deletions src/plugins/vis_type_vega/public/default.spec.hjson
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
{
/*
/*

Welcome to Vega visualizations. Here you can design your own dataviz from scratch using a declarative language called Vega, or its simpler form Vega-Lite. In Vega, you have the full control of what data is loaded, even from multiple sources, how that data is transformed, and what visual elements are used to show it. Use help icon to view Vega examples, tutorials, and other docs. Use the wrench icon to reformat this text, or to remove comments.
Welcome to Vega visualizations. Here you can design your own dataviz from scratch using a declarative language called Vega, or its simpler form Vega-Lite. In Vega, you have the full control of what data is loaded, even from multiple sources, how that data is transformed, and what visual elements are used to show it. Use help icon to view Vega examples, tutorials, and other docs. Use the wrench icon to reformat this text, or to remove comments.

This example graph shows the document count in all indexes in the current time range. You might need to adjust the time filter in the upper right corner.
*/
This example graph shows the document count in all indexes in the current time range. You might need to adjust the time filter in the upper right corner.
*/

$schema: https://vega.github.io/schema/vega-lite/v4.json
$schema: https://vega.github.io/schema/vega-lite/v5.json
title: Event counts from all indexes

// Define the data source
data: {
url: {
/*
An object instead of a string for the "url" param is treated as an OpenSearch query. Anything inside this object is not part of the Vega language, but only understood by OpenSearch Dashboards and OpenSearch server. This query counts the number of documents per time interval, assuming you have a @timestamp field in your data.
/*
An object instead of a string for the "url" param is treated as an OpenSearch query. Anything inside this object is not part of the Vega language, but only understood by OpenSearch Dashboards and OpenSearch server. This query counts the number of documents per time interval, assuming you have a @timestamp field in your data.

OpenSearch Dashboards has a special handling for the fields surrounded by "%". They are processed before the the query is sent to OpenSearch. This way the query becomes context aware, and can use the time range and the dashboard filters.
*/
OpenSearch Dashboards has a special handling for the fields surrounded by "%". They are processed before the the query is sent to OpenSearch. This way the query becomes context aware, and can use the time range and the dashboard filters.
*/

// Apply dashboard context filters when set
%context%: true
// Filter the time picker (upper right corner) with this field
%timefield%: @timestamp

/*
See .search() documentation for : https://opensearch.org/docs/latest/clients/javascript/
*/
/*
See .search() documentation for : https://opensearch.org/docs/latest/clients/javascript/
*/

// Which index to search
index: _all
Expand Down Expand Up @@ -53,29 +53,29 @@ See .search() documentation for : https://opensearch.org/docs/latest/clients/ja
size: 0
}
}
/*
OpenSearch will return results in this format:
/*
OpenSearch will return results in this format:

aggregations: {
time_buckets: {
buckets: [
{
key_as_string: 2015-11-30T22:00:00.000Z
key: 1448920800000
doc_count: 0
},
{
key_as_string: 2015-11-30T23:00:00.000Z
key: 1448924400000
doc_count: 0
aggregations: {
time_buckets: {
buckets: [
{
key_as_string: 2015-11-30T22:00:00.000Z
key: 1448920800000
doc_count: 0
},
{
key_as_string: 2015-11-30T23:00:00.000Z
key: 1448924400000
doc_count: 0
}
...
]
}
...
]
}
}
}

For our graph, we only need the list of bucket values. Use the format.property to discard everything else.
*/
For our graph, we only need the list of bucket values. Use the format.property to discard everything else.
*/
format: {property: "aggregations.time_buckets.buckets"}
}

Expand Down
5 changes: 4 additions & 1 deletion src/plugins/vis_type_vega/public/lib/vega.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@
* under the License.
*/

import * as vegaLite from 'vega-lite/build-es5/vega-lite';
// Build vega-lite from source for es5 compatibility
import { compile, version } from 'vega-lite-next/src';
import * as vega from 'vega/build-es5/vega';
import { expressionInterpreter as vegaExpressionInterpreter } from 'vega-interpreter/build/vega-interpreter.module';

const vegaLite = { compile, version };

export { vega, vegaLite, vegaExpressionInterpreter };
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"title": "Event counts from all indexes",
"data": {
"url": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"format": {"property": "aggregations.time_buckets.buckets"},
"values": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jest.mock('./default_spec', () => ({

jest.mock('./lib/vega', () => ({
vega: jest.requireActual('vega'),
vegaLite: jest.requireActual('vega-lite'),
vegaLite: jest.requireActual('vega-lite-next/src'),
}));

// FLAKY: https://github.com/elastic/kibana/issues/71713
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const mockedSavedObjects = [
visState: JSON.stringify({
type: 'vega',
params: {
spec: '{"$schema": "https://vega.github.io/schema/vega-lite/v4.json" }',
spec: '{"$schema": "https://vega.github.io/schema/vega-lite/v5.json" }',
},
}),
},
Expand Down
74 changes: 70 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5"
integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==

"@babel/helper-plugin-utils@^7.20.2":
version "7.20.2"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629"
integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==

"@babel/helper-remap-async-to-generator@^7.16.8":
version "7.16.8"
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3"
Expand Down Expand Up @@ -495,6 +500,14 @@
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-syntax-json-strings" "^7.8.3"

"@babel/plugin-proposal-logical-assignment-operators@^7.16.5":
version "7.20.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz#dfbcaa8f7b4d37b51e8bfb46d94a5aea2bb89d83"
integrity sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==
dependencies:
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"

"@babel/plugin-proposal-logical-assignment-operators@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea"
Expand Down Expand Up @@ -2742,7 +2755,7 @@
resolved "https://registry.yarnpkg.com/@types/chroma-js/-/chroma-js-2.1.3.tgz#0b03d737ff28fad10eb884e0c6cedd5ffdc4ba0a"
integrity sha512-1xGPhoSGY1CPmXLCBcjVZSQinFjL26vlR8ZqprsBWiFyED4JacJJ9zHhh5aaUXqbY9B37mKQ73nlydVAXmr1+g==

"@types/clone@~2.1.0":
"@types/clone@~2.1.0", "@types/clone@~2.1.1":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@types/clone/-/clone-2.1.1.tgz#9b880d0ce9b1f209b5e0bd6d9caa38209db34024"
integrity sha512-BZIU34bSYye0j/BFcPraiDZ5ka6MJADjcDVELGf7glr9K+iE8NYVjFslJFVWzskSxkLLyCrSPScE82/UUoBSvg==
Expand Down Expand Up @@ -4104,9 +4117,9 @@ acorn@^7.0.0, acorn@^7.1.1:
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==

acorn@^8.2.4:
version "8.7.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
version "8.8.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73"
integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==

[email protected]:
version "0.5.9"
Expand Down Expand Up @@ -5727,6 +5740,15 @@ cliui@^7.0.0, cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"

cliui@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.1"
wrap-ansi "^7.0.0"

clone-buffer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
Expand Down Expand Up @@ -11442,6 +11464,11 @@ json-stringify-pretty-compact@~2.0.0:
resolved "https://registry.yarnpkg.com/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz#e77c419f52ff00c45a31f07f4c820c2433143885"
integrity sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==

json-stringify-pretty-compact@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz#f71ef9d82ef16483a407869556588e91b681d9ab"
integrity sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==

[email protected], json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
Expand Down Expand Up @@ -17116,6 +17143,11 @@ tslib@~2.0.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c"
integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==

tslib@~2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==

tsutils@^3.17.1, tsutils@^3.21.0:
version "3.21.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
Expand Down Expand Up @@ -17825,6 +17857,22 @@ vega-label@~1.2.0:
vega-scenegraph "^4.9.2"
vega-util "^1.15.2"

"vega-lite-next@npm:vega-lite@^5.6.0":
version "5.6.0"
resolved "https://registry.yarnpkg.com/vega-lite/-/vega-lite-5.6.0.tgz#0f0adfc8b86f5eea071df186b2877d828c870c11"
integrity sha512-aTjQk//SzL9ctHY4ItA8yZSGflHMWPJmCXEs8LeRlixuOaAbamZmeL8xNMbQpS/vAZQeFAqjcJ32Fuztz/oGww==
dependencies:
"@types/clone" "~2.1.1"
clone "~2.1.2"
fast-deep-equal "~3.1.3"
fast-json-stable-stringify "~2.1.0"
json-stringify-pretty-compact "~3.0.0"
tslib "~2.4.0"
vega-event-selector "~3.0.0"
vega-expression "~5.0.0"
vega-util "~1.17.0"
yargs "~17.6.0"

vega-lite@^4.16.8:
version "4.17.0"
resolved "https://registry.yarnpkg.com/vega-lite/-/vega-lite-4.17.0.tgz#01ad4535e92f28c3852c1071711de272ddfb4631"
Expand Down Expand Up @@ -18705,6 +18753,11 @@ yargs-parser@^20.0.0, yargs-parser@^20.2.2, yargs-parser@^20.2.3:
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==

yargs-parser@^21.1.1:
version "21.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==

[email protected]:
version "1.6.0"
resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f"
Expand Down Expand Up @@ -18773,6 +18826,19 @@ yargs@~16.0.3:
y18n "^5.0.1"
yargs-parser "^20.0.0"

yargs@~17.6.0:
version "17.6.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.2.tgz#2e23f2944e976339a1ee00f18c77fedee8332541"
integrity sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==
dependencies:
cliui "^8.0.1"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
y18n "^5.0.5"
yargs-parser "^21.1.1"

yauzl@^2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
Expand Down