From 8b303469e50db8515fd2b9f9aabad006cc0175fc Mon Sep 17 00:00:00 2001 From: Miki Date: Wed, 2 Nov 2022 13:34:41 -0700 Subject: [PATCH 01/25] Update backport workflow to ignore changelog conflicts (#2729) Signed-off-by: Miki Signed-off-by: Miki --- .github/workflows/backport.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index f515b254b868..1d05b4169306 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -22,10 +22,9 @@ jobs: # opensearch-trigger-bot installation ID installation_id: 22958780 - # Using fork of https://github.com/tibdex/backport - # https://github.com/tibdex/backport/pull/81 - name: Backport - uses: VachaShah/backport@v1.1.4 + uses: VachaShah/backport@v2.1.0 with: github_token: ${{ steps.github_app_token.outputs.token }} branch_name: backport/backport-${{ github.event.number }} + files_to_skip: "CHANGELOG.md" From 9436dd3dbafc37f8548d9b602a92fff7490a3a18 Mon Sep 17 00:00:00 2001 From: Kristen Tian <105667444+kristenTian@users.noreply.github.com> Date: Wed, 2 Nov 2022 16:40:54 -0700 Subject: [PATCH 02/25] Tweak multiple data source design doc (#2724) Signed-off-by: Kristen Tian Signed-off-by: Kristen Tian --- CHANGELOG.md | 2 ++ .../client_management_design.md | 22 +++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e859e023e260..0c540af6bed1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,8 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### 📝 Documentation * [MD] Add design documents of multiple data source feature [#2538](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2538) +* [MD] Tweak multiple data source design doc [#2724](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2724) + ### 🛠 Maintenance - Adding @zhongnansu as maintainer. ([#2590](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2590)) diff --git a/docs/multi-datasource/client_management_design.md b/docs/multi-datasource/client_management_design.md index 389e2e408255..c83b254fe289 100644 --- a/docs/multi-datasource/client_management_design.md +++ b/docs/multi-datasource/client_management_design.md @@ -39,8 +39,8 @@ This design is part of the OpenSearch Dashboards multi data source project [[RFC ### 4.0 Answer some critical design questions -**1.** **How to set up connection(clients) for different datasources?** -Similar to how current OpenSearch Dashboards talks to default OS by creating opensearch node.js client using [opensearch-js](https://github.com/opensearch-project/opensearch-js) library, for datasources we also create clients for each. Critical params that differentiate data sources are `url` and `auth` +**1.** **How to set up connection(clients) for different data sources?** +Similar to how current OpenSearch Dashboards talks to default OpenSearch by creating a client using [opensearch-js](https://github.com/opensearch-project/opensearch-js) library, for data sources we also create clients for each connection. Critical params that differentiate data sources are `url` and `auth` ```ts const { Client } = require('@opensearch-project/opensearch'); @@ -59,7 +59,7 @@ dataSourceClient.ping(); ``` **2. How to expose datasource clients to callers through clean interfaces?** -We create a `data source service`. Similar to existing `opensearch service` in core, which provides client of default OS cluster. This new service will be dedicated to provide clients for data sources. Following the same paradigm we can register this new service to `CoreStart`, `CoreRouteHandlerContext` , in order to expose data source client to plugins and modules. The interface is exposed from new service, and thus it doesn’t mess up with any existing services, and keeps the interface clean. +We create a `data source service`. Similar to existing `opensearch service` in core, which provides client of default OpenSearch cluster. This new service will be dedicated to provide clients for data sources. Following the same paradigm we can register this new service to `CoreStart`, `CoreRouteHandlerContext` , in order to expose data source client to plugins and modules. The interface is exposed from new service, and thus it doesn’t mess up with any existing services, and keeps the interface clean. ``` *// Existing* @@ -77,14 +77,14 @@ The context is that user can only turn on/off multiple datasource feature by upd **4.How to manage multiple clients/connection efficiently, and not consume all the memory?** -- For datasources with different endpoint, user client Pooling (E.g. LRU cache) +- For data sources with different endpoint, user client Pooling (E.g. LRU cache) - For data sources with same endpoint, but different user, use connection pooling strategy (child client) provided by opensearch-js. **5.Where should we implement the core logic?** Current `opensearch service` exists in core. The module we'll implement has similarity function wise, but we choose to implement `data source service` in plugin along with `crypto` service for the following reasons. -1. Data source is a feature that can be turned on or off. Plugin is born for such plugable use case. -2. We don't mess up with OpenSearch Dashboards core, since this is an experimental feature, the potential risk of breaking existing behavior will be lower if we use plugin. Worst case, user could just uninstall the plugin. +1. Data source is a feature that can be turned on or off. Plugin is born for such pluggable use case. +2. We don't mess up with OpenSearch Dashboards core, since this is an experimental feature, the potential risk of breaking existing behavior will be lowered if we use plugin. Worst case, user could just uninstall the plugin. 3. Complexity wise, it's about the same amount of work. ### 4.1 Data Source Plugin @@ -130,14 +130,14 @@ We need to configure the data source client by either creating a new one, or loo } ``` -- Get root client: Look up client Pool by **endpoint**, return client if existed. If misses, we create new client instance and load into pool. At this step, the client won't have any auth info. +- Get root client: Look up the client pool by **endpoint** and return the client if it exists. If a client was not found, a new client instance is created and loaded into pool. At this step, the client won't have any auth info. - Get credentials: Call crypto service utilities to **decrypt** user credentials from `DataSource` Object. -- Assemble the actual query client: With auth info and root client, we’ll leverage the openearch-js connection pooling strategy to create the actual query client from root client by `client.child()`. +- Assemble the actual query client: With auth info and root client, we’ll leverage the `opensearch-js` connection pooling strategy to create the actual query client from root client by `client.child()`. #### 4.2.1 Legacy Client -OpenSearch Dashboards is forked from Kibana 7.10. At the time of the fork happened, there are 2 types of client used in the codebase. One is the new client, which later was migrated as `opensearhc-js`, the other one is the legacy client which is `elasticsearc-js`. Legacy clients are still used many critical features, such as visualization, index pattern management, along with new client. +OpenSearch Dashboards had two types of clients available for use when created. One was the "new client" which has since been separated into `opensearch-js`, and the other was the legacy client named `elasticsearch-js`. Legacy clients are still used by some core features like visualization and index pattern management. ```ts // legacy client @@ -174,7 +174,7 @@ This is for plugin to access data source client via request handler. For example ### 4.4 Refactor data plugin search module to call core API to get datasource client -`Search strategy` is the low level API of data plugin search module. It retrieve clients and query OpenSearch. It needs to be refactored to switch between default client and datasource client, depending on whether a request is send to datasource or not. +`Search strategy` is the low level API of data plugin search module. It retrieves clients and queries OpenSearch. It needs to be refactored to switch between the default client and the datasource client, depending on whether or not a request is sent to the datasource. Currently default client is retrieved by search module of data plugin to interact with OpenSearch by this API call. Ref: [opensearch-search-strategy.ts](https://github.com/opensearch-project/opensearch-dashboards/blob/e3b34df1dea59a253884f6da4e49c3e717d362c9/src/plugins/data/server/search/opensearch_search/opensearch_search_strategy.ts#L75) @@ -184,7 +184,7 @@ const client: OpenSearchClient = core.opensearch.client.asCurrentUser; client.search(params); ``` -Similarly we’ll have the following for datasource use case. `AsCurrentUser` is something doesn’t make sense for datasource, because it’s always the “current” user credential defined in the “datasource”, that we are using to create the client, or look up the client pool. +Similarly we’ll have the following for datasource use case. `AsCurrentUser` doesn't really apply to a datasource because it’s always the “current” user's credentials, defined in the “datasource”, that gets used to initialize the client or lookup the client pool. ```ts if (request.dataSource) { From b53d4d878e2f307033e46298b3fa14b6ec1bd37e Mon Sep 17 00:00:00 2001 From: Josh Romero Date: Wed, 2 Nov 2022 19:49:49 -0700 Subject: [PATCH 03/25] [Chore] Refactor and improve Discover field summaries (#2391) * [Chore] Refactor and improve field summaries * Convert to typescript * Fix types * Add tests Signed-off-by: Josh Romero * [Test] Update functional test Groups are now naturally sorted by key, which requires selecting a different date filter Signed-off-by: Josh Romero * [Chore] Add changelog entry Signed-off-by: Josh Romero * [Chore] Refactor columns passing, fix bugs * pass columns explicitly as props * fix branding in core mocks * fix `toBeUndefined()` usage in tests * remove leftover comment * fix test subject * condense types Signed-off-by: Josh Romero Signed-off-by: Josh Romero --- CHANGELOG.md | 4 +- src/core/public/mocks.ts | 1 + .../sidebar/discover_field.test.tsx | 4 +- .../components/sidebar/discover_field.tsx | 10 +- .../sidebar/discover_field_bucket.tsx | 4 +- .../sidebar/discover_field_details.test.tsx | 218 +++++++++++++++++- .../sidebar/discover_field_details.tsx | 56 ++--- .../components/sidebar/discover_sidebar.tsx | 7 +- .../sidebar/lib/field_calculator.js | 150 ------------ .../sidebar/lib/field_calculator.test.ts | 158 ++++++++----- .../sidebar/lib/field_calculator.ts | 148 ++++++++++++ .../components/sidebar/lib/get_details.ts | 21 +- .../application/components/sidebar/types.ts | 7 +- .../apps/management/_scripted_fields.js | 4 +- 14 files changed, 526 insertions(+), 266 deletions(-) delete mode 100644 src/plugins/discover/public/application/components/sidebar/lib/field_calculator.js create mode 100644 src/plugins/discover/public/application/components/sidebar/lib/field_calculator.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c540af6bed1..0b3c2d3d6e66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,7 +68,9 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Adding @zhongnansu as maintainer. ([#2590](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2590)) ### 🪛 Refactoring -* [MD] Refactor data source error handling ([#2661](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2661)) + +- [MD] Refactor data source error handling ([#2661](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2661)) +- Refactor and improve Discover field summaries ([#2391](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2391)) ### 🔩 Tests diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts index 163e34b4cf1a..e863d627c801 100644 --- a/src/core/public/mocks.ts +++ b/src/core/public/mocks.ts @@ -83,6 +83,7 @@ function createCoreSetupMock({ uiSettings: uiSettingsServiceMock.createSetupContract(), injectedMetadata: { getInjectedVar: injectedMetadataServiceMock.createSetupContract().getInjectedVar, + getBranding: injectedMetadataServiceMock.createSetupContract().getBranding, }, }; diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx index 39c5c0abed0d..1b384a4b5550 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx @@ -29,6 +29,7 @@ */ import React from 'react'; +// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; // @ts-ignore import stubbedLogstashFields from 'fixtures/logstash_fields'; @@ -99,8 +100,9 @@ function getComponent({ const props = { indexPattern, + columns: [], field: finalField, - getDetails: jest.fn(() => ({ buckets: [], error: '', exists: 1, total: true, columns: [] })), + getDetails: jest.fn(() => ({ buckets: [], error: '', exists: 1, total: 1 })), onAddFilter: jest.fn(), onAddField: jest.fn(), onRemoveField: jest.fn(), diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field.tsx index 157cb88e782a..e807267435eb 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field.tsx @@ -40,6 +40,10 @@ import { getFieldTypeName } from './lib/get_field_type_name'; import './discover_field.scss'; export interface DiscoverFieldProps { + /** + * the selected columns displayed in the doc table in discover + */ + columns: string[]; /** * The displayed field */ @@ -76,6 +80,7 @@ export interface DiscoverFieldProps { } export function DiscoverField({ + columns, field, indexPattern, onAddField, @@ -228,9 +233,10 @@ export function DiscoverField({ {infoIsOpen && ( )} diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field_bucket.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field_bucket.tsx index 1f1af8e91331..6a4dbe295e50 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field_bucket.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field_bucket.tsx @@ -68,7 +68,7 @@ export function DiscoverFieldBucket({ field, bucket, onAddFilter }: Props) { title={ bucket.display === '' ? emptyTxt - : `${bucket.display}: ${bucket.count} (${bucket.percent}%)` + : `${bucket.display}: ${bucket.count} (${bucket.percent.toFixed(1)}%)` } size="xs" className="eui-textTruncate" @@ -78,7 +78,7 @@ export function DiscoverFieldBucket({ field, bucket, onAddFilter }: Props) { - {bucket.percent}% + {bucket.percent.toFixed(1)}% diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field_details.test.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field_details.test.tsx index c57300f3032b..63d5c7ace303 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field_details.test.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field_details.test.tsx @@ -29,15 +29,26 @@ */ import React from 'react'; +// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; +import { act } from '@testing-library/react'; // @ts-ignore import stubbedLogstashFields from 'fixtures/logstash_fields'; -import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers'; import { DiscoverFieldDetails } from './discover_field_details'; import { coreMock } from '../../../../../../core/public/mocks'; import { IndexPatternField } from '../../../../../data/public'; import { getStubIndexPattern } from '../../../../../data/public/test_utils'; +const mockGetHref = jest.fn(); +const mockGetTriggerCompatibleActions = jest.fn(); + +jest.mock('../../../opensearch_dashboards_services', () => ({ + getUiActions: () => ({ + getTriggerCompatibleActions: mockGetTriggerCompatibleActions, + }), +})); + const indexPattern = getStubIndexPattern( 'logstash-*', (cfg: any) => cfg, @@ -48,17 +59,187 @@ const indexPattern = getStubIndexPattern( describe('discover sidebar field details', function () { const defaultProps = { + columns: [], + details: { buckets: [], error: '', exists: 1, total: 1 }, indexPattern, - details: { buckets: [], error: '', exists: 1, total: true, columns: [] }, onAddFilter: jest.fn(), }; - function mountComponent(field: IndexPatternField) { - const compProps = { ...defaultProps, field }; + beforeEach(() => { + mockGetHref.mockReturnValue('/foo/bar'); + mockGetTriggerCompatibleActions.mockReturnValue([ + { + getHref: mockGetHref, + }, + ]); + }); + + function mountComponent(field: IndexPatternField, props?: Record) { + const compProps = { ...defaultProps, ...props, field }; return mountWithIntl(); } - it('should enable the visualize link for a number field', function () { + it('should render buckets if they exist', async function () { + const visualizableField = new IndexPatternField( + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + 'bytes' + ); + const buckets = [1, 2, 3].map((n) => ({ + display: `display-${n}`, + value: `value-${n}`, + percent: 25, + count: 100, + })); + const comp = mountComponent(visualizableField, { + details: { ...defaultProps.details, buckets }, + }); + expect(findTestSubject(comp, 'fieldVisualizeError').length).toBe(0); + expect(findTestSubject(comp, 'fieldVisualizeBucketContainer').length).toBe(1); + expect(findTestSubject(comp, 'fieldVisualizeBucketContainer').children().length).toBe( + buckets.length + ); + // Visualize link should not be rendered until async hook update + expect(findTestSubject(comp, 'fieldVisualizeLink').length).toBe(0); + expect(findTestSubject(comp, 'fieldVisualize-bytes').length).toBe(0); + + // Complete async hook + await act(async () => { + await nextTick(); + comp.update(); + }); + expect(findTestSubject(comp, 'fieldVisualizeError').length).toBe(0); + expect(findTestSubject(comp, 'fieldVisualizeBucketContainer').length).toBe(1); + expect(findTestSubject(comp, 'fieldVisualizeBucketContainer').children().length).toBe( + buckets.length + ); + expect(findTestSubject(comp, 'fieldVisualizeLink').length).toBe(1); + expect(findTestSubject(comp, 'fieldVisualize-bytes').length).toBe(1); + }); + + it('should only render buckets if they exist', async function () { + const visualizableField = new IndexPatternField( + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + 'bytes' + ); + const comp = mountComponent(visualizableField); + expect(findTestSubject(comp, 'fieldVisualizeContainer').length).toBe(1); + expect(findTestSubject(comp, 'fieldVisualizeError').length).toBe(0); + expect(findTestSubject(comp, 'fieldVisualizeBucketContainer').length).toBe(0); + expect(findTestSubject(comp, 'fieldVisualizeLink').length).toBe(0); + expect(findTestSubject(comp, 'fieldVisualize-bytes').length).toBe(0); + + await act(async () => { + await nextTick(); + comp.update(); + }); + + expect(findTestSubject(comp, 'fieldVisualizeContainer').length).toBe(1); + expect(findTestSubject(comp, 'fieldVisualizeError').length).toBe(0); + expect(findTestSubject(comp, 'fieldVisualizeBucketContainer').length).toBe(0); + expect(findTestSubject(comp, 'fieldVisualizeLink').length).toBe(1); + expect(findTestSubject(comp, 'fieldVisualize-bytes').length).toBe(1); + }); + + it('should render a details error', async function () { + const visualizableField = new IndexPatternField( + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + 'bytes' + ); + const errText = 'Some error'; + const comp = mountComponent(visualizableField, { + details: { ...defaultProps.details, error: errText }, + }); + expect(findTestSubject(comp, 'fieldVisualizeContainer').length).toBe(1); + expect(findTestSubject(comp, 'fieldVisualizeBucketContainer').length).toBe(0); + expect(findTestSubject(comp, 'fieldVisualizeError').length).toBe(1); + expect(findTestSubject(comp, 'fieldVisualizeError').text()).toBe(errText); + + await act(async () => { + await nextTick(); + comp.update(); + }); + expect(findTestSubject(comp, 'fieldVisualizeLink').length).toBe(1); + expect(findTestSubject(comp, 'fieldVisualize-bytes').length).toBe(1); + }); + + it('should handle promise rejection from isFieldVisualizable', async function () { + mockGetTriggerCompatibleActions.mockRejectedValue(new Error('Async error')); + const visualizableField = new IndexPatternField( + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + 'bytes' + ); + const comp = mountComponent(visualizableField); + + await act(async () => { + await nextTick(); + comp.update(); + }); + expect(findTestSubject(comp, 'fieldVisualizeLink').length).toBe(0); + expect(findTestSubject(comp, 'fieldVisualize-bytes').length).toBe(0); + }); + + it('should handle promise rejection from getVisualizeHref', async function () { + mockGetHref.mockRejectedValue(new Error('Async error')); + const visualizableField = new IndexPatternField( + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + 'bytes' + ); + const comp = mountComponent(visualizableField); + + await act(async () => { + await nextTick(); + comp.update(); + }); + expect(findTestSubject(comp, 'fieldVisualizeLink').length).toBe(0); + expect(findTestSubject(comp, 'fieldVisualize-bytes').length).toBe(0); + }); + + it('should enable the visualize link for a number field', async function () { const visualizableField = new IndexPatternField( { name: 'bytes', @@ -73,10 +254,17 @@ describe('discover sidebar field details', function () { 'bytes' ); const comp = mountComponent(visualizableField); - expect(findTestSubject(comp, 'fieldVisualize-bytes')).toBeTruthy(); + + await act(async () => { + await nextTick(); + comp.update(); + }); + expect(findTestSubject(comp, 'fieldVisualizeLink').length).toBe(1); + expect(findTestSubject(comp, 'fieldVisualize-bytes').length).toBe(1); }); - it('should disable the visualize link for an _id field', function () { + it('should disable the visualize link for an _id field', async function () { + expect.assertions(1); const conflictField = new IndexPatternField( { name: '_id', @@ -91,10 +279,15 @@ describe('discover sidebar field details', function () { 'test' ); const comp = mountComponent(conflictField); - expect(findTestSubject(comp, 'fieldVisualize-_id')).toEqual({}); + + await act(async () => { + await nextTick(); + comp.update(); + }); + expect(findTestSubject(comp, 'fieldVisualize-_id').length).toBe(0); }); - it('should disable the visualize link for an unknown field', function () { + it('should disable the visualize link for an unknown field', async function () { const unknownField = new IndexPatternField( { name: 'test', @@ -109,6 +302,11 @@ describe('discover sidebar field details', function () { 'test' ); const comp = mountComponent(unknownField); - expect(findTestSubject(comp, 'fieldVisualize-test')).toEqual({}); + + await act(async () => { + await nextTick(); + comp.update(); + }); + expect(findTestSubject(comp, 'fieldVisualize-test').length).toBe(0); }); }); diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field_details.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field_details.tsx index 1fbcebbc0c8c..906c173ed07d 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field_details.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field_details.tsx @@ -43,16 +43,18 @@ import { IndexPatternField, IndexPattern } from '../../../../../data/public'; import './discover_field_details.scss'; interface DiscoverFieldDetailsProps { + columns: string[]; + details: FieldDetails; field: IndexPatternField; indexPattern: IndexPattern; - details: FieldDetails; onAddFilter: (field: IndexPatternField | string, value: string, type: '+' | '-') => void; } export function DiscoverFieldDetails({ + columns, + details, field, indexPattern, - details, onAddFilter, }: DiscoverFieldDetailsProps) { const warnings = getWarnings(field); @@ -60,37 +62,37 @@ export function DiscoverFieldDetails({ const [visualizeLink, setVisualizeLink] = useState(''); useEffect(() => { - isFieldVisualizable(field, indexPattern.id, details.columns).then( - (flag) => { - setShowVisualizeLink(flag); - // get href only if Visualize button is enabled - getVisualizeHref(field, indexPattern.id, details.columns).then( - (uri) => { - if (uri) setVisualizeLink(uri); - }, - () => { - setVisualizeLink(''); - } - ); - }, - () => { - setShowVisualizeLink(false); + const checkIfVisualizable = async () => { + const visualizable = await isFieldVisualizable(field, indexPattern.id, columns).catch( + () => false + ); + + setShowVisualizeLink(visualizable); + if (visualizable) { + const href = await getVisualizeHref(field, indexPattern.id, columns).catch(() => ''); + setVisualizeLink(href || ''); } - ); - }, [field, indexPattern.id, details.columns]); + }; + checkIfVisualizable(); + }, [field, indexPattern.id, columns]); const handleVisualizeLinkClick = (event: React.MouseEvent) => { // regular link click. let the uiActions code handle the navigation and show popup if needed event.preventDefault(); - triggerVisualizeActions(field, indexPattern.id, details.columns); + triggerVisualizeActions(field, indexPattern.id, columns); }; return ( <> -
- {details.error && {details.error}} - {!details.error && ( -
+
+ {details.error && ( + + {details.error} + + )} + + {!details.error && details.buckets.length > 0 && ( +
{details.buckets.map((bucket: Bucket, idx: number) => ( )} - {showVisualizeLink && ( - <> + {showVisualizeLink && visualizeLink && ( +
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */} 0 && ( )} - +
)}
{!details.error && ( diff --git a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx index f957b93a4cc4..865aff590286 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx @@ -117,8 +117,8 @@ export function DiscoverSidebar({ ); const getDetailsByField = useCallback( - (ipField: IndexPatternField) => getDetails(ipField, hits, columns, selectedIndexPattern), - [hits, columns, selectedIndexPattern] + (ipField: IndexPatternField) => getDetails(ipField, hits, selectedIndexPattern), + [hits, selectedIndexPattern] ); const popularLimit = services.uiSettings.get(FIELDS_LIMIT_SETTING); @@ -199,6 +199,7 @@ export function DiscoverSidebar({ className="dscSidebar__item" > ; - let params: any; - let values: any; + let grouped: boolean; + let values: any[]; beforeEach(function () { values = [ ['foo', 'bar'], @@ -88,30 +76,28 @@ describe('fieldCalculator', function () { 'foo', undefined, ]; - params = {}; - groups = fieldCalculator._groupValues(values, params); + groups = groupValues(values, grouped); }); - it('should have a _groupValues that counts values', function () { + it('should return an object values', function () { expect(groups).toBeInstanceOf(Object); }); it('should throw an error if any value is a plain object', function () { expect(function () { - fieldCalculator._groupValues([{}, true, false], params); + groupValues([{}, true, false], grouped); }).toThrowError(); }); it('should handle values with dots in them', function () { values = ['0', '0.........', '0.......,.....']; - params = {}; - groups = fieldCalculator._groupValues(values, params); + groups = groupValues(values, grouped); expect(groups[values[0]].count).toBe(1); expect(groups[values[1]].count).toBe(1); expect(groups[values[2]].count).toBe(1); }); - it('should have a a key for value in the array when not grouping array terms', function () { + it('should have a key for value in the array when not grouping array terms', function () { expect(_.keys(groups).length).toBe(3); expect(groups.foo).toBeInstanceOf(Object); expect(groups.bar).toBeInstanceOf(Object); @@ -119,7 +105,7 @@ describe('fieldCalculator', function () { }); it('should count array terms independently', function () { - expect(groups['foo,bar']).toBe(undefined); + expect(groups['foo,bar']).toBeUndefined(); expect(groups.foo.count).toBe(5); expect(groups.bar.count).toBe(3); expect(groups.baz.count).toBe(1); @@ -127,11 +113,11 @@ describe('fieldCalculator', function () { describe('grouped array terms', function () { beforeEach(function () { - params.grouped = true; - groups = fieldCalculator._groupValues(values, params); + grouped = true; + groups = groupValues(values, grouped); }); - it('should group array terms when passed params.grouped', function () { + it('should group array terms when grouped is true', function () { expect(_.keys(groups).length).toBe(4); expect(groups['foo,bar']).toBeInstanceOf(Object); }); @@ -155,12 +141,12 @@ describe('fieldCalculator', function () { hits = _.each(_.cloneDeep(realHits), (hit) => indexPattern.flattenHit(hit)); }); - it('Should return an array of values for _source fields', function () { - const extensions = fieldCalculator.getFieldValues( + it('should return an array of values for _source fields', function () { + const extensions = getFieldValues({ hits, - indexPattern.fields.getByName('extension'), - indexPattern - ); + field: indexPattern.fields.getByName('extension') as IndexPatternField, + indexPattern, + }); expect(extensions).toBeInstanceOf(Array); expect( _.filter(extensions, function (v) { @@ -170,12 +156,12 @@ describe('fieldCalculator', function () { expect(_.uniq(_.clone(extensions)).sort()).toEqual(['gif', 'html', 'php', 'png']); }); - it('Should return an array of values for core meta fields', function () { - const types = fieldCalculator.getFieldValues( + it('should return an array of values for core meta fields', function () { + const types = getFieldValues({ hits, - indexPattern.fields.getByName('_type'), - indexPattern - ); + field: indexPattern.fields.getByName('_type') as IndexPatternField, + indexPattern, + }); expect(types).toBeInstanceOf(Array); expect( _.filter(types, function (v) { @@ -187,48 +173,96 @@ describe('fieldCalculator', function () { }); describe('getFieldValueCounts', function () { - let params: { hits: any; field: any; count: number; indexPattern: IndexPattern }; + let params: FieldValueCountsParams; beforeEach(function () { params = { hits: _.cloneDeep(realHits), - field: indexPattern.fields.getByName('extension'), + field: indexPattern.fields.getByName('extension') as IndexPatternField, count: 3, indexPattern, }; }); + it('counts the top 5 values by default', function () { + params.hits = params.hits.map((hit: Record, i) => ({ + ...hit, + _source: { + extension: `${hit._source.extension}-${i}`, + }, + })); + params.count = undefined; + const extensions = getFieldValueCounts(params); + expect(extensions).toBeInstanceOf(Object); + expect(extensions.buckets).toBeInstanceOf(Array); + const buckets = extensions.buckets as Bucket[]; + expect(buckets.length).toBe(5); + expect(extensions.error).toBeUndefined(); + }); + + it('counts only distinct values if less than default', function () { + params.count = undefined; + const extensions = getFieldValueCounts(params); + expect(extensions).toBeInstanceOf(Object); + expect(extensions.buckets).toBeInstanceOf(Array); + const buckets = extensions.buckets as Bucket[]; + expect(buckets.length).toBe(4); + expect(extensions.error).toBeUndefined(); + }); + + it('counts only distinct values if less than specified count', function () { + params.count = 10; + const extensions = getFieldValueCounts(params); + expect(extensions).toBeInstanceOf(Object); + expect(extensions.buckets).toBeInstanceOf(Array); + const buckets = extensions.buckets as Bucket[]; + expect(buckets.length).toBe(4); + expect(extensions.error).toBeUndefined(); + }); + it('counts the top 3 values', function () { - const extensions = fieldCalculator.getFieldValueCounts(params); + const extensions = getFieldValueCounts(params); expect(extensions).toBeInstanceOf(Object); expect(extensions.buckets).toBeInstanceOf(Array); - expect(extensions.buckets.length).toBe(3); - expect(_.map(extensions.buckets, 'value')).toEqual(['html', 'php', 'gif']); - expect(extensions.error).toBe(undefined); + const buckets = extensions.buckets as Bucket[]; + expect(buckets.length).toBe(3); + expect(_.map(buckets, 'value')).toEqual(['html', 'gif', 'php']); + expect(extensions.error).toBeUndefined(); }); it('fails to analyze geo and attachment types', function () { - params.field = indexPattern.fields.getByName('point'); - expect(fieldCalculator.getFieldValueCounts(params).error).not.toBe(undefined); + params.field = indexPattern.fields.getByName('point') as IndexPatternField; + expect(getFieldValueCounts(params).error).not.toBeUndefined(); - params.field = indexPattern.fields.getByName('area'); - expect(fieldCalculator.getFieldValueCounts(params).error).not.toBe(undefined); + params.field = indexPattern.fields.getByName('area') as IndexPatternField; + expect(getFieldValueCounts(params).error).not.toBeUndefined(); - params.field = indexPattern.fields.getByName('request_body'); - expect(fieldCalculator.getFieldValueCounts(params).error).not.toBe(undefined); + params.field = indexPattern.fields.getByName('request_body') as IndexPatternField; + expect(getFieldValueCounts(params).error).not.toBeUndefined(); }); it('fails to analyze fields that are in the mapping, but not the hits', function () { - params.field = indexPattern.fields.getByName('ip'); - expect(fieldCalculator.getFieldValueCounts(params).error).not.toBe(undefined); + params.field = indexPattern.fields.getByName('ip') as IndexPatternField; + expect(getFieldValueCounts(params).error).not.toBeUndefined(); }); it('counts the total hits', function () { - expect(fieldCalculator.getFieldValueCounts(params).total).toBe(params.hits.length); + expect(getFieldValueCounts(params).total).toBe(params.hits.length); }); it('counts the hits the field exists in', function () { - params.field = indexPattern.fields.getByName('phpmemory'); - expect(fieldCalculator.getFieldValueCounts(params).exists).toBe(5); + params.field = indexPattern.fields.getByName('phpmemory') as IndexPatternField; + expect(getFieldValueCounts(params).exists).toBe(5); + }); + + it('catches and returns errors', function () { + params.hits = params.hits.map((hit: Record) => ({ + ...hit, + _source: { + extension: { foo: hit._source.extension }, + }, + })); + params.grouped = true; + expect(typeof getFieldValueCounts(params).error).toBe('string'); }); }); }); diff --git a/src/plugins/discover/public/application/components/sidebar/lib/field_calculator.ts b/src/plugins/discover/public/application/components/sidebar/lib/field_calculator.ts new file mode 100644 index 000000000000..54f8832fa1fc --- /dev/null +++ b/src/plugins/discover/public/application/components/sidebar/lib/field_calculator.ts @@ -0,0 +1,148 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@osd/i18n'; +import { IndexPattern, IndexPatternField } from 'src/plugins/data/public'; +import { FieldValueCounts } from '../types'; + +const NO_ANALYSIS_TYPES = ['geo_point', 'geo_shape', 'attachment']; + +interface FieldValuesParams { + hits: Array>; + field: IndexPatternField; + indexPattern: IndexPattern; +} + +interface FieldValueCountsParams extends FieldValuesParams { + count?: number; + grouped?: boolean; +} + +const getFieldValues = ({ hits, field, indexPattern }: FieldValuesParams) => { + const name = field.name; + const flattenHit = indexPattern.flattenHit; + return hits.map((hit) => flattenHit(hit)[name]); +}; + +const getFieldValueCounts = (params: FieldValueCountsParams): FieldValueCounts => { + const { hits, field, indexPattern, count = 5, grouped = false } = params; + const { type: fieldType } = field; + + if (NO_ANALYSIS_TYPES.includes(fieldType)) { + return { + error: i18n.translate( + 'discover.fieldChooser.fieldCalculator.analysisIsNotAvailableForGeoFieldsErrorMessage', + { + defaultMessage: 'Analysis is not available for {fieldType} fields.', + values: { + fieldType, + }, + } + ), + }; + } + + const allValues = getFieldValues({ hits, field, indexPattern }); + const missing = allValues.filter((v) => v === undefined || v === null).length; + + try { + const groups = groupValues(allValues, grouped); + const counts = Object.keys(groups) + .sort((a, b) => groups[b].count - groups[a].count) + .slice(0, count) + .map((key) => ({ + value: groups[key].value, + count: groups[key].count, + percent: (groups[key].count / (hits.length - missing)) * 100, + display: indexPattern.getFormatterForField(field).convert(groups[key].value), + })); + + if (hits.length === missing) { + return { + error: i18n.translate( + 'discover.fieldChooser.fieldCalculator.fieldIsNotPresentInDocumentsErrorMessage', + { + defaultMessage: + 'This field is present in your OpenSearch mapping but not in the {hitsLength} documents shown in the doc table. You may still be able to visualize or search on it.', + values: { + hitsLength: hits.length, + }, + } + ), + }; + } + + return { + total: hits.length, + exists: hits.length - missing, + missing, + buckets: counts, + }; + } catch (e) { + return { + error: e instanceof Error ? e.message : String(e), + }; + } +}; + +const groupValues = ( + allValues: any[], + grouped?: boolean +): Record => { + const values = grouped ? allValues : allValues.flat(); + + return values + .filter((v) => { + if (v instanceof Object && !Array.isArray(v)) { + throw new Error( + i18n.translate( + 'discover.fieldChooser.fieldCalculator.analysisIsNotAvailableForObjectFieldsErrorMessage', + { + defaultMessage: 'Analysis is not available for object fields.', + } + ) + ); + } + return v !== undefined && v !== null; + }) + .reduce((groups, value) => { + if (groups.hasOwnProperty(value)) { + groups[value].count++; + } else { + groups[value] = { + value, + count: 1, + }; + } + return groups; + }, {}); +}; + +export { FieldValueCountsParams, groupValues, getFieldValues, getFieldValueCounts }; diff --git a/src/plugins/discover/public/application/components/sidebar/lib/get_details.ts b/src/plugins/discover/public/application/components/sidebar/lib/get_details.ts index fb8f22e202cd..823cbde9ba72 100644 --- a/src/plugins/discover/public/application/components/sidebar/lib/get_details.ts +++ b/src/plugins/discover/public/application/components/sidebar/lib/get_details.ts @@ -29,27 +29,38 @@ */ // @ts-ignore -import { fieldCalculator } from './field_calculator'; +import { i18n } from '@osd/i18n'; +import { getFieldValueCounts } from './field_calculator'; import { IndexPattern, IndexPatternField } from '../../../../../../data/public'; export function getDetails( field: IndexPatternField, hits: Array>, - columns: string[], indexPattern?: IndexPattern ) { + const defaultDetails = { + error: '', + exists: 0, + total: 0, + buckets: [], + }; if (!indexPattern) { - return {}; + return { + ...defaultDetails, + error: i18n.translate('discover.fieldChooser.noIndexPatternSelectedErrorMessage', { + defaultMessage: 'Index pattern not specified.', + }), + }; } const details = { - ...fieldCalculator.getFieldValueCounts({ + ...defaultDetails, + ...getFieldValueCounts({ hits, field, indexPattern, count: 5, grouped: false, }), - columns, }; if (details.buckets) { for (const bucket of details.buckets) { diff --git a/src/plugins/discover/public/application/components/sidebar/types.ts b/src/plugins/discover/public/application/components/sidebar/types.ts index b254057b0de0..a43120b28e96 100644 --- a/src/plugins/discover/public/application/components/sidebar/types.ts +++ b/src/plugins/discover/public/application/components/sidebar/types.ts @@ -36,9 +36,12 @@ export interface IndexPatternRef { export interface FieldDetails { error: string; exists: number; - total: boolean; + total: number; buckets: Bucket[]; - columns: string[]; +} + +export interface FieldValueCounts extends Partial { + missing?: number; } export interface Bucket { diff --git a/test/functional/apps/management/_scripted_fields.js b/test/functional/apps/management/_scripted_fields.js index cbd1169e7a33..9ce2a57436e1 100644 --- a/test/functional/apps/management/_scripted_fields.js +++ b/test/functional/apps/management/_scripted_fields.js @@ -509,10 +509,10 @@ export default function ({ getService, getPageObjects }) { it('should filter by scripted field value in Discover', async function () { await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); - await log.debug('filter by "Sep 17, 2015 @ 23:00" in the expanded scripted field list'); + await log.debug('filter by "Sep 18, 2015 @ 7:52" in the expanded scripted field list'); await PageObjects.discover.clickFieldListPlusFilter( scriptedPainlessFieldName2, - '1442531297065' + '1442562775953' ); await PageObjects.header.waitUntilLoadingHasFinished(); From f6cbd1d2417c4d3c5dfd44669e7c159141cc7f68 Mon Sep 17 00:00:00 2001 From: Bandini <63824432+bandinib-amzn@users.noreply.github.com> Date: Wed, 2 Nov 2022 19:52:59 -0700 Subject: [PATCH 04/25] Removes Add Integration button (#2723) * Removes Add Integration button Issue Resolved: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2684 Signed-off-by: Bandini Bhopi * Adds changelog entry Signed-off-by: Bandini Bhopi Signed-off-by: Bandini Bhopi --- CHANGELOG.md | 1 + .../__snapshots__/empty_state.test.tsx.snap | 27 ------------------- .../empty_state/empty_state.tsx | 3 ++- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b3c2d3d6e66..f18363317d24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Multi DataSource] Apply get indices error handling in step index pattern ([#2652](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2652)) - [Vis Builder] Last Updated Timestamp for visbuilder savedobject is getting Generated ([#2628](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2628)) - Removed Leftover X Pack references ([#2638](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2638)) +- Removes Add Integration button ([#2723](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2723)) ### 🚞 Infrastructure diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/__snapshots__/empty_state.test.tsx.snap b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/__snapshots__/empty_state.test.tsx.snap index 4b18bf314541..a617fa0511e2 100644 --- a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/__snapshots__/empty_state.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/__snapshots__/empty_state.test.tsx.snap @@ -30,33 +30,6 @@ exports[`EmptyState should render normally 1`] = ` columns={3} responsive={true} > - - - } - icon={ - - } - onClick={[Function]} - title={ - - } - /> - + {/* TODO: [UNCOMMENTME] Once we have long-term fix for https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2684 } /> - + */} {getMlCardState() !== MlCardState.HIDDEN ? mlCard : <>} Date: Wed, 2 Nov 2022 20:21:26 -0700 Subject: [PATCH 05/25] Prevent backport workflow from running on umerged PRs (#2746) Signed-off-by: Miki Signed-off-by: Miki --- .github/workflows/backport.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 1d05b4169306..cb2e3c3049c6 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -12,6 +12,17 @@ jobs: contents: write pull-requests: write name: Backport + # Only react to merged PRs for security reasons. + # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. + if: > + github.event.pull_request.merged + && ( + github.event.action == 'closed' + || ( + github.event.action == 'labeled' + && contains(github.event.label.name, 'backport') + ) + ) steps: - name: GitHub App token id: github_app_token From 82eb0e896e530cd0d1918683845e4eb2fd6a903d Mon Sep 17 00:00:00 2001 From: Ashwin P Chandran Date: Wed, 2 Nov 2022 20:42:16 -0700 Subject: [PATCH 06/25] [Vis Builder] Enable VisBuilder cypress tests (#2728) * Enable VisBuilder cypress tests Signed-off-by: Ashwin P Chandran * Adds changelog and fix env Signed-off-by: Ashwin P Chandran * Run all tests Signed-off-by: Ashwin P Chandran Signed-off-by: Ashwin P Chandran --- .github/workflows/cypress_workflow.yml | 5 +++-- CHANGELOG.md | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cypress_workflow.yml b/.github/workflows/cypress_workflow.yml index afe33c85ce17..41b9d46aa32f 100644 --- a/.github/workflows/cypress_workflow.yml +++ b/.github/workflows/cypress_workflow.yml @@ -11,7 +11,8 @@ env: FTR_PATH: 'ftr' START_CMD: 'node ../scripts/opensearch_dashboards --dev --no-base-path --no-watch' OPENSEARCH_SNAPSHOT_CMD: 'node ../scripts/opensearch snapshot' - SPEC: 'cypress/integration/core-opensearch-dashboards/opensearch-dashboards/*.js,' + SPEC: 'cypress/integration/core-opensearch-dashboards/opensearch-dashboards/**/*.js,' + CYPRESS_ENV: 'env CYPRESS_VISBUILDER_ENABLED=true ' jobs: cypress-tests: @@ -75,7 +76,7 @@ jobs: working-directory: ${{ env.FTR_PATH }} start: ${{ env.OPENSEARCH_SNAPSHOT_CMD }}, ${{ env.START_CMD }} wait-on: 'http://localhost:9200, http://localhost:5601' - command: yarn cypress:run-without-security --browser chromium --spec ${{ env.SPEC }} + command: ${{ env.CYPRESS_ENV }} yarn cypress:run-without-security --browser chromium --spec ${{ env.SPEC }} # Screenshots are only captured on failure, will change this once we do visual regression tests - uses: actions/upload-artifact@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index f18363317d24..35a7438ef7f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Vis Builder] Rename wizard to visBuilder in i18n id and formatted message id ([#2635](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2635)) - [Vis Builder] Rename wizard to visBuilder in class name, type name and function name ([#2639](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2639)) - [Vis Builder] Rename wizard on save modal and visualization table ([#2645](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2645)) +- [Vis Builder] Adds functional tests to CI ([#2728](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2728)) - [Vis Builder] Enable VisBuilder by default ([#2725](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2725)) - Change save object type, wizard id and name to visBuilder #2673 ([#2673](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2673)) - [Multi DataSource] Update MD data source documentation link ([#2693](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2693)) From 810307c960dfffcc080521d6cb9dc608699032be Mon Sep 17 00:00:00 2001 From: Kawika Avilla Date: Thu, 3 Nov 2022 11:55:05 -0700 Subject: [PATCH 07/25] [CI] update backport custom branch name (#2766) GitHub action for backporting got updated to change custom branch to head template. This was causing issues in clean up and skipping steps. Issue: n/a Signed-off-by: Kawika Avilla --- .github/workflows/backport.yml | 2 +- CHANGELOG.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index cb2e3c3049c6..0ba694cbf213 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -37,5 +37,5 @@ jobs: uses: VachaShah/backport@v2.1.0 with: github_token: ${{ steps.github_app_token.outputs.token }} - branch_name: backport/backport-${{ github.event.number }} + head_template: backport/backport-<%= number %>-to-<%= base %> files_to_skip: "CHANGELOG.md" diff --git a/CHANGELOG.md b/CHANGELOG.md index 35a7438ef7f5..e1c1d514494a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### 🚞 Infrastructure - Add CHANGELOG.md and related workflows ([#2414](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2414)) +- Update backport custom branch name to utilize head template ([#2766](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2766)) ### 📝 Documentation From 19a2e4a9156f04cfd87aa6961919129e19b5eac3 Mon Sep 17 00:00:00 2001 From: Miki Date: Thu, 3 Nov 2022 16:35:14 -0700 Subject: [PATCH 08/25] [Legacy Maps Plugin] Prevent reverse-tabnabbing (#2540) Signed-off-by: Miki Signed-off-by: Miki --- CHANGELOG.md | 2 ++ src/plugins/maps_legacy/public/map/map_messages.js | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1c1d514494a..058e5a05120e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### 🛡 Security +* [Legacy Maps Plugin] Prevent reverse-tabnabbing ([#2540](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2540)) + ### 📈 Features/Enhancements - [MD] Support legacy client for data source ([#2204](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2204)) diff --git a/src/plugins/maps_legacy/public/map/map_messages.js b/src/plugins/maps_legacy/public/map/map_messages.js index e87161c1ba1f..9606a72f959c 100644 --- a/src/plugins/maps_legacy/public/map/map_messages.js +++ b/src/plugins/maps_legacy/public/map/map_messages.js @@ -32,7 +32,7 @@ import React, { Fragment } from 'react'; import ReactDOM from 'react-dom'; import { FormattedMessage } from '@osd/i18n/react'; -import { EuiSpacer, EuiButtonEmpty, EuiEmptyPrompt } from '@elastic/eui'; +import { EuiSpacer, EuiButtonEmpty, EuiEmptyPrompt, EuiLink } from '@elastic/eui'; import { toMountPoint } from '../../../opensearch_dashboards_react/public'; export const createRegionDeniedWarning = (function () { @@ -112,9 +112,12 @@ export const createZoomWarningMsg = (function () { Please go to { wms } for more information." values={{ wms: ( - + {`Custom WMS Configuration`} - + ), }} /> From 3da0396c76869e283b72db306386dd5a1ee6cb63 Mon Sep 17 00:00:00 2001 From: Anan Zhuang Date: Thu, 3 Nov 2022 17:42:04 -0700 Subject: [PATCH 09/25] change geckodriver version to make consistency (#2772) * change geckodriver version to make consistency Issue Resolved: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2771 Signed-off-by: Anan Zhuang * combine https-proxy-agent in yarn.lock Signed-off-by: Anan Zhuang Signed-off-by: Anan Zhuang --- CHANGELOG.md | 3 ++- package.json | 2 +- yarn.lock | 18 +++++++++--------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 058e5a05120e..158ef8adb3fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,8 +55,9 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Multi DataSource] Address UX comments on index pattern management stack ([#2611](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2611)) - [Multi DataSource] Apply get indices error handling in step index pattern ([#2652](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2652)) - [Vis Builder] Last Updated Timestamp for visbuilder savedobject is getting Generated ([#2628](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2628)) -- Removed Leftover X Pack references ([#2638](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2638)) +- Removed Leftover X Pack references ([#2638](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2638)) - Removes Add Integration button ([#2723](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2723)) +- Change geckodriver version to make consistency ([#2772](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2772)) ### 🚞 Infrastructure diff --git a/package.json b/package.json index 437412617326..f74e858b68c3 100644 --- a/package.json +++ b/package.json @@ -377,7 +377,7 @@ "exit-hook": "^2.2.0", "fetch-mock": "^7.3.9", "fp-ts": "^2.3.1", - "geckodriver": "^3.0.1", + "geckodriver": "^3.0.2", "getopts": "^2.2.5", "grunt": "^1.5.2", "grunt-available-tasks": "^0.6.3", diff --git a/yarn.lock b/yarn.lock index 7c7726328e15..2ed05fd39fa0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9071,15 +9071,15 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -geckodriver@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-3.0.2.tgz#6bd69166a24859c5edbc6ece9868339378b6c97b" - integrity sha512-GHOQzQnTeZOJdcdEXLuzmcRwkbHuei1VivXkn2BLyleKiT6lTvl0T7vm+d0wvr/EZC7jr0m1u1pBHSfqtuFuNQ== +geckodriver@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-3.2.0.tgz#6b0a85e2aafbce209bca30e2d53af857707b1034" + integrity sha512-p+qR2RKlI/TQoCEYrSuTaYCLqsJNni96WmEukTyXmOmLn+3FLdgPAEwMZ0sG2Cwi9hozUzGAWyT6zLuhF6cpiQ== dependencies: adm-zip "0.5.9" bluebird "3.7.2" got "11.8.5" - https-proxy-agent "5.0.0" + https-proxy-agent "5.0.1" tar "6.1.11" gensync@^1.0.0-beta.2: @@ -10102,10 +10102,10 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== +https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== dependencies: agent-base "6" debug "4" From a7b9d169b4b419c01bec742589a939901332a6b3 Mon Sep 17 00:00:00 2001 From: Anan Zhuang Date: Thu, 3 Nov 2022 17:42:45 -0700 Subject: [PATCH 10/25] [Vis Builder] Add an experimental table visualization in vis builder (#2705) * [Vis Builder] Add an experimental table visualization in vis builder In this PR, we hook up an experimental table vis in vis builder. This table vis is a refactor of previous table. It is written in React and DataGrid component. In this PR, we did two main things: * add an experimental table visualization * enable it in vis builder Issue Resolved (hook up table in vis builder): https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2704 The experimental table vis has all the features from current table, including * restore table vis in react using a Datagrid component * datagrid component does not support splitted grids. For future transfer to OUI Datagrid, we create a tableGroup in visData for splitted grids. * restore basic pagenation, sort and format. * implement datagrid columns * display column title correctly * deangular and re-use formatted column * convert formatted column to data grid column * restore filter in and filter out value functions * format table cell to show Date and percent * restore showTotal feature: it allows table vis to show total, avg, min, max and count statics on count * restore export csv feature to table vis * split table in rows and columns Beside of restoring original features, there are some changes: * [IMPROVE] remove repeated column from split tables Currently, when we split table by columns, the split column is shown both in the table title and as a separate column. This is not needed. In this PR, we remove the repeated column in split tables in col. * [NEW FEATURE] adjustable table column width In the new table visualization, customer can adjust the column width as needed. Issue Resolved: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2212 https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2213 https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2305 https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2379 https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2579 Since this is a hookup PR, we remove un-used table vis types and options because they could be defined in vis builder. We also create follow up issues for some un-resolved PR comments. Signed-off-by: Anan Zhuang * remove unused scss tyle Signed-off-by: Anan Zhuang * remove total func and percentage col total func and percentage col are two features that we might need to remove or re-invent for future table vis. For hookup purpose, it doesn't make sense to include some features that we would like to remove. this PR removes total func and percentage col in both table vis and vis builder Signed-off-by: Anan Zhuang * comment out cellActions currently filter in/out cell doesn't function in vis builder. we will coumment out cell actions for now. Signed-off-by: Anan Zhuang Signed-off-by: Anan Zhuang --- CHANGELOG.md | 1 + src/plugins/vis_builder/README.md | 2 +- .../utils/use/use_saved_vis_builder_vis.ts | 3 +- .../common/expression_helpers.ts | 10 +- .../public/visualizations/index.ts | 2 + .../table/components/table_viz_options.tsx | 109 +++++++++++++ .../public/visualizations/table/index.ts | 6 + .../visualizations/table/table_viz_type.ts | 95 +++++++++++ .../visualizations/table/to_expression.ts | 130 +++++++++++++++ src/plugins/vis_type_table_new/README.md | 1 + .../opensearch_dashboards.json | 16 ++ .../public/components/table_vis_app.scss | 14 ++ .../public/components/table_vis_app.tsx | 71 +++++++++ .../public/components/table_vis_component.tsx | 142 +++++++++++++++++ .../components/table_vis_component_group.tsx | 38 +++++ .../public/components/table_vis_control.tsx | 55 +++++++ .../components/table_vis_grid_columns.tsx | 148 ++++++++++++++++++ .../vis_type_table_new/public/index.ts | 13 ++ .../vis_type_table_new/public/plugin.ts | 36 +++++ .../vis_type_table_new/public/services.ts | 11 ++ .../vis_type_table_new/public/table_vis_fn.ts | 65 ++++++++ .../public/table_vis_renderer.tsx | 36 +++++ .../public/table_vis_response_handler.ts | 112 +++++++++++++ .../vis_type_table_new/public/types.ts | 70 +++++++++ .../public/utils/convert_to_csv_data.ts | 85 ++++++++++ .../public/utils/convert_to_formatted_data.ts | 68 ++++++++ .../vis_type_table_new/public/utils/index.ts | 8 + .../public/utils/use_pagination.ts | 39 +++++ 28 files changed, 1380 insertions(+), 6 deletions(-) create mode 100644 src/plugins/vis_builder/public/visualizations/table/components/table_viz_options.tsx create mode 100644 src/plugins/vis_builder/public/visualizations/table/index.ts create mode 100644 src/plugins/vis_builder/public/visualizations/table/table_viz_type.ts create mode 100644 src/plugins/vis_builder/public/visualizations/table/to_expression.ts create mode 100644 src/plugins/vis_type_table_new/README.md create mode 100644 src/plugins/vis_type_table_new/opensearch_dashboards.json create mode 100644 src/plugins/vis_type_table_new/public/components/table_vis_app.scss create mode 100644 src/plugins/vis_type_table_new/public/components/table_vis_app.tsx create mode 100644 src/plugins/vis_type_table_new/public/components/table_vis_component.tsx create mode 100644 src/plugins/vis_type_table_new/public/components/table_vis_component_group.tsx create mode 100644 src/plugins/vis_type_table_new/public/components/table_vis_control.tsx create mode 100644 src/plugins/vis_type_table_new/public/components/table_vis_grid_columns.tsx create mode 100644 src/plugins/vis_type_table_new/public/index.ts create mode 100644 src/plugins/vis_type_table_new/public/plugin.ts create mode 100644 src/plugins/vis_type_table_new/public/services.ts create mode 100644 src/plugins/vis_type_table_new/public/table_vis_fn.ts create mode 100644 src/plugins/vis_type_table_new/public/table_vis_renderer.tsx create mode 100644 src/plugins/vis_type_table_new/public/table_vis_response_handler.ts create mode 100644 src/plugins/vis_type_table_new/public/types.ts create mode 100644 src/plugins/vis_type_table_new/public/utils/convert_to_csv_data.ts create mode 100644 src/plugins/vis_type_table_new/public/utils/convert_to_formatted_data.ts create mode 100644 src/plugins/vis_type_table_new/public/utils/index.ts create mode 100644 src/plugins/vis_type_table_new/public/utils/use_pagination.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 158ef8adb3fc..b2ad560973bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Multi DataSource] Update MD data source documentation link ([#2693](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2693)) - [Save Object Aggregation View] Add extension point in saved object management to register namespaces and show filter ([#2656](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2656)) - [Save Object Aggregation View] Fix for export all after scroll count response changed in PR#2656 ([#2696](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2696)) +- [Vis Builder] Add an experimental table visualization in vis builder ([#2705](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2705)) ### 🐛 Bug Fixes diff --git a/src/plugins/vis_builder/README.md b/src/plugins/vis_builder/README.md index 88b5afbda1f4..4bbf82d9dc87 100755 --- a/src/plugins/vis_builder/README.md +++ b/src/plugins/vis_builder/README.md @@ -31,6 +31,6 @@ Outline: **Notes:** -- Currently only the metric viz is defined, so schema properties that other vis types might need may be missing and require further setup. +- Currently only the metric and table viz are defined, so schema properties that other vis types might need may be missing and require further setup. - `to_expression` has not yet been abstracted into a common utility for different visualizations. Adding more visualization types should make it easier to identify which parts of expression creation are common, and which are visualization-specific. diff --git a/src/plugins/vis_builder/public/application/utils/use/use_saved_vis_builder_vis.ts b/src/plugins/vis_builder/public/application/utils/use/use_saved_vis_builder_vis.ts index d7840b92f8ad..6e5d861c5318 100644 --- a/src/plugins/vis_builder/public/application/utils/use/use_saved_vis_builder_vis.ts +++ b/src/plugins/vis_builder/public/application/utils/use/use_saved_vis_builder_vis.ts @@ -13,7 +13,6 @@ import { } from '../../../../../opensearch_dashboards_utils/public'; import { EDIT_PATH, PLUGIN_ID } from '../../../../common'; import { VisBuilderServices } from '../../../types'; -import { MetricOptionsDefaults } from '../../../visualizations/metric/metric_viz_type'; import { getCreateBreadcrumbs, getEditBreadcrumbs } from '../breadcrumbs'; import { getSavedVisBuilderVis } from '../get_saved_vis_builder_vis'; import { @@ -81,7 +80,7 @@ export const useSavedVisBuilderVis = (visualizationIdFromUrl: string | undefined } } - dispatch(setStyleState(styleState)); + dispatch(setStyleState(styleState)); dispatch(setVisualizationState(visualizationState)); } diff --git a/src/plugins/vis_builder/public/visualizations/common/expression_helpers.ts b/src/plugins/vis_builder/public/visualizations/common/expression_helpers.ts index 069666677d60..f50ab9172cdb 100644 --- a/src/plugins/vis_builder/public/visualizations/common/expression_helpers.ts +++ b/src/plugins/vis_builder/public/visualizations/common/expression_helpers.ts @@ -9,8 +9,12 @@ import { ExpressionFunctionOpenSearchDashboards } from '../../../../expressions' import { buildExpressionFunction } from '../../../../expressions/public'; import { VisualizationState } from '../../application/utils/state_management'; import { getSearchService, getIndexPatterns } from '../../plugin_services'; +import { StyleState } from '../../application/utils/state_management'; -export const getAggExpressionFunctions = async (visualization: VisualizationState) => { +export const getAggExpressionFunctions = async ( + visualization: VisualizationState, + style?: StyleState +) => { const { activeVisualization, indexPattern: indexId = '' } = visualization; const { aggConfigParams } = activeVisualization || {}; @@ -32,8 +36,8 @@ export const getAggExpressionFunctions = async (visualization: VisualizationStat 'opensearchaggs', { index: indexId, - metricsAtAllLevels: false, - partialRows: false, + metricsAtAllLevels: style?.showMetricsAtAllLevels || false, + partialRows: style?.showPartialRows || false, aggConfigs: JSON.stringify(aggConfigs.aggs), includeFormatHints: false, } diff --git a/src/plugins/vis_builder/public/visualizations/index.ts b/src/plugins/vis_builder/public/visualizations/index.ts index 6787c28a6ff8..c867e570143e 100644 --- a/src/plugins/vis_builder/public/visualizations/index.ts +++ b/src/plugins/vis_builder/public/visualizations/index.ts @@ -5,6 +5,7 @@ import type { TypeServiceSetup } from '../services/type_service'; import { createMetricConfig } from './metric'; +import { createTableConfig } from './table'; import { createHistogramConfig, createLineConfig, createAreaConfig } from './vislib'; export function registerDefaultTypes(typeServiceSetup: TypeServiceSetup) { @@ -13,6 +14,7 @@ export function registerDefaultTypes(typeServiceSetup: TypeServiceSetup) { createLineConfig, createAreaConfig, createMetricConfig, + createTableConfig, ]; visualizationTypes.forEach((createTypeConfig) => { diff --git a/src/plugins/vis_builder/public/visualizations/table/components/table_viz_options.tsx b/src/plugins/vis_builder/public/visualizations/table/components/table_viz_options.tsx new file mode 100644 index 000000000000..8c934fff8dac --- /dev/null +++ b/src/plugins/vis_builder/public/visualizations/table/components/table_viz_options.tsx @@ -0,0 +1,109 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { get } from 'lodash'; +import React, { useCallback, useEffect, useMemo } from 'react'; +import { i18n } from '@osd/i18n'; +import { FormattedMessage } from '@osd/i18n/react'; +import produce from 'immer'; +import { Draft } from 'immer'; +import { EuiIconTip } from '@elastic/eui'; +import { search } from '../../../../../data/public'; +import { NumberInputOption, SwitchOption } from '../../../../../charts/public'; +import { + useTypedDispatch, + useTypedSelector, + setStyleState, +} from '../../../application/utils/state_management'; +import { TableOptionsDefaults } from '../table_viz_type'; +import { Option } from '../../../application/app'; + +function TableVizOptions() { + const styleState = useTypedSelector((state) => state.style) as TableOptionsDefaults; + const dispatch = useTypedDispatch(); + + const setOption = useCallback( + (callback: (draft: Draft) => void) => { + const newState = produce(styleState, callback); + dispatch(setStyleState(newState)); + }, + [dispatch, styleState] + ); + + const isPerPageValid = styleState.perPage === '' || styleState.perPage > 0; + + return ( + <> + + + ); +} + +export { TableVizOptions }; diff --git a/src/plugins/vis_builder/public/visualizations/table/index.ts b/src/plugins/vis_builder/public/visualizations/table/index.ts new file mode 100644 index 000000000000..51fd19d291e7 --- /dev/null +++ b/src/plugins/vis_builder/public/visualizations/table/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { createTableConfig } from './table_viz_type'; diff --git a/src/plugins/vis_builder/public/visualizations/table/table_viz_type.ts b/src/plugins/vis_builder/public/visualizations/table/table_viz_type.ts new file mode 100644 index 000000000000..733ad986f289 --- /dev/null +++ b/src/plugins/vis_builder/public/visualizations/table/table_viz_type.ts @@ -0,0 +1,95 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { Schemas } from '../../../../vis_default_editor/public'; +import { AggGroupNames } from '../../../../data/public'; +import { TableVizOptions } from './components/table_viz_options'; +import { VisualizationTypeOptions } from '../../services/type_service'; +import { toExpression } from './to_expression'; + +export interface TableOptionsDefaults { + perPage: number | ''; + showPartialRows: boolean; + showMetricsAtAllLevels: boolean; +} + +export const createTableConfig = (): VisualizationTypeOptions => ({ + name: 'table', + title: 'Table', + icon: 'visTable', + description: 'Display table visualizations', + toExpression, + ui: { + containerConfig: { + data: { + schemas: new Schemas([ + { + group: AggGroupNames.Metrics, + name: 'metric', + title: i18n.translate('visTypeTableNewNew.tableVisEditorConfig.schemas.metricTitle', { + defaultMessage: 'Metric', + }), + min: 1, + aggFilter: ['!geo_centroid', '!geo_bounds'], + aggSettings: { + top_hits: { + allowStrings: true, + }, + }, + defaults: { + aggTypes: ['avg', 'cardinality'], + }, + }, + { + group: AggGroupNames.Buckets, + name: 'bucket', + title: i18n.translate('visTypeTableNewNew.tableVisEditorConfig.schemas.bucketTitle', { + defaultMessage: 'Split rows', + }), + aggFilter: ['!filter'], + defaults: { + aggTypes: ['terms'], + }, + }, + { + group: AggGroupNames.Buckets, + name: 'split_row', + title: i18n.translate('visTypeTableNewNew.tableVisEditorConfig.schemas.splitTitle', { + defaultMessage: 'Split table in rows', + }), + min: 0, + max: 1, + aggFilter: ['!filter'], + defaults: { + aggTypes: ['terms'], + }, + }, + { + group: AggGroupNames.Buckets, + name: 'split_column', + title: i18n.translate('visTypeTableNewNew.tableVisEditorConfig.schemas.splitTitle', { + defaultMessage: 'Split table in columns', + }), + min: 0, + max: 1, + aggFilter: ['!filter'], + defaults: { + aggTypes: ['terms'], + }, + }, + ]), + }, + style: { + defaults: { + perPage: 10, + showPartialRows: false, + showMetricsAtAllLevels: false, + }, + render: TableVizOptions, + }, + }, + }, +}); diff --git a/src/plugins/vis_builder/public/visualizations/table/to_expression.ts b/src/plugins/vis_builder/public/visualizations/table/to_expression.ts new file mode 100644 index 000000000000..212c93248d40 --- /dev/null +++ b/src/plugins/vis_builder/public/visualizations/table/to_expression.ts @@ -0,0 +1,130 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SchemaConfig } from '../../../../visualizations/public'; +import { TableVisExpressionFunctionDefinition } from '../../../../vis_type_table_new/public'; +import { AggConfigs, IAggConfig } from '../../../../data/common'; +import { buildExpression, buildExpressionFunction } from '../../../../expressions/public'; +import { RenderState } from '../../application/utils/state_management'; +import { TableOptionsDefaults } from './table_viz_type'; +import { getAggExpressionFunctions } from '../common/expression_helpers'; + +// TODO: Update to the common getShemas from src/plugins/visualizations/public/legacy/build_pipeline.ts +// And move to a common location accessible by all the visualizations +const getVisSchemas = (aggConfigs: AggConfigs, showMetricsAtAllLevels: boolean): any => { + const createSchemaConfig = (accessor: number, agg: IAggConfig): SchemaConfig => { + const hasSubAgg = [ + 'derivative', + 'moving_avg', + 'serial_diff', + 'cumulative_sum', + 'sum_bucket', + 'avg_bucket', + 'min_bucket', + 'max_bucket', + ].includes(agg.type.name); + + const formatAgg = hasSubAgg + ? agg.params.customMetric || agg.aggConfigs.getRequestAggById(agg.params.metricAgg) + : agg; + + const params = {}; + + const label = agg.makeLabel && agg.makeLabel(); + + return { + accessor, + format: formatAgg.toSerializedFieldFormat(), + params, + label, + aggType: agg.type.name, + }; + }; + + let cnt = 0; + const schemas: any = { + metric: [], + }; + + if (!aggConfigs) { + return schemas; + } + + const responseAggs = aggConfigs.getResponseAggs().filter((agg: IAggConfig) => agg.enabled); + const metrics = responseAggs.filter((agg: IAggConfig) => agg.type.type === 'metrics'); + + responseAggs.forEach((agg) => { + let skipMetrics = false; + const schemaName = agg.schema; + + if (!schemaName) { + cnt++; + return; + } + + if (schemaName === 'split_row' || schemaName === 'split_column') { + skipMetrics = responseAggs.length - metrics.length > 1; + } + + if (!schemas[schemaName]) { + schemas[schemaName] = []; + } + + if (!showMetricsAtAllLevels || agg.type.type !== 'metrics') { + schemas[schemaName]!.push(createSchemaConfig(cnt++, agg)); + } + + if ( + showMetricsAtAllLevels && + (agg.type.type !== 'metrics' || metrics.length === responseAggs.length) + ) { + metrics.forEach((metric: any) => { + const schemaConfig = createSchemaConfig(cnt++, metric); + if (!skipMetrics) { + schemas.metric.push(schemaConfig); + } + }); + } + }); + + return schemas; +}; + +export interface TableRootState extends RenderState { + style: TableOptionsDefaults; +} + +export const toExpression = async ({ style: styleState, visualization }: TableRootState) => { + const { aggConfigs, expressionFns } = await getAggExpressionFunctions(visualization, styleState); + const { showPartialRows, showMetricsAtAllLevels } = styleState; + + const schemas = getVisSchemas(aggConfigs, showMetricsAtAllLevels); + + const metrics = + schemas.bucket && showPartialRows && !showMetricsAtAllLevels + ? schemas.metric.slice(-1 * (schemas.metric.length / schemas.bucket.length)) + : schemas.metric; + + const tableData = { + metrics, + buckets: schemas.bucket || [], + splitRow: schemas.split_row, + splitColumn: schemas.split_column, + }; + + const visConfig = { + ...styleState, + ...tableData, + }; + + const tableVis = buildExpressionFunction( + 'opensearch_dashboards_table_new', + { + visConfig: JSON.stringify(visConfig), + } + ); + + return buildExpression([...expressionFns, tableVis]).toString(); +}; diff --git a/src/plugins/vis_type_table_new/README.md b/src/plugins/vis_type_table_new/README.md new file mode 100644 index 000000000000..06299ed963a2 --- /dev/null +++ b/src/plugins/vis_type_table_new/README.md @@ -0,0 +1 @@ +Contains the data table visualization, that allows presenting data using a Datagrid component. diff --git a/src/plugins/vis_type_table_new/opensearch_dashboards.json b/src/plugins/vis_type_table_new/opensearch_dashboards.json new file mode 100644 index 000000000000..598ca7581b83 --- /dev/null +++ b/src/plugins/vis_type_table_new/opensearch_dashboards.json @@ -0,0 +1,16 @@ +{ + "id": "visTypeTableNew", + "version": "opensearchDashboards", + "server": false, + "ui": true, + "requiredPlugins": [ + "expressions", + "visualizations", + "data" + ], + "requiredBundles": [ + "opensearchDashboardsUtils", + "opensearchDashboardsReact", + "share" + ] +} diff --git a/src/plugins/vis_type_table_new/public/components/table_vis_app.scss b/src/plugins/vis_type_table_new/public/components/table_vis_app.scss new file mode 100644 index 000000000000..af6558774da3 --- /dev/null +++ b/src/plugins/vis_type_table_new/public/components/table_vis_app.scss @@ -0,0 +1,14 @@ +.visTable__group { + padding: $euiSizeS; + margin-bottom: $euiSizeL; + + > h3 { + text-align: center; + } +} + +.visTable__groupInColumns { + display: flex; + flex-direction: row; + align-items: flex-start; +} diff --git a/src/plugins/vis_type_table_new/public/components/table_vis_app.tsx b/src/plugins/vis_type_table_new/public/components/table_vis_app.tsx new file mode 100644 index 000000000000..7958b2187620 --- /dev/null +++ b/src/plugins/vis_type_table_new/public/components/table_vis_app.tsx @@ -0,0 +1,71 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import './table_vis_app.scss'; +import React, { useEffect, useState } from 'react'; +import classNames from 'classnames'; +import { CoreStart } from 'opensearch-dashboards/public'; +import { I18nProvider } from '@osd/i18n/react'; +import { IInterpreterRenderHandlers } from 'src/plugins/expressions'; +import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public'; +import { TableContext } from '../table_vis_response_handler'; +import { TableVisConfig, SortColumn, ColumnWidth, TableUiState } from '../types'; +import { TableVisComponent } from './table_vis_component'; +import { TableVisComponentGroup } from './table_vis_component_group'; + +interface TableVisAppProps { + services: CoreStart; + visData: TableContext; + visConfig: TableVisConfig; + handlers: IInterpreterRenderHandlers; +} + +export const TableVisApp = ({ + services, + visData: { table, tableGroups, direction }, + visConfig, + handlers, +}: TableVisAppProps) => { + // Rendering is asynchronous, completed by handlers.done() + useEffect(() => { + handlers.done(); + }, [handlers]); + + const className = classNames('visTable', { + // eslint-disable-next-line @typescript-eslint/naming-convention + visTable__groupInColumns: direction === 'column', + }); + + // TODO: remove duplicate sort and width state + // Issue: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2704#issuecomment-1299380818 + const [sort, setSort] = useState({ colIndex: null, direction: null }); + const [width, setWidth] = useState([]); + + const tableUiState: TableUiState = { sort, setSort, width, setWidth }; + + return ( + + +
+ {table ? ( + + ) : ( + + )} +
+
+
+ ); +}; diff --git a/src/plugins/vis_type_table_new/public/components/table_vis_component.tsx b/src/plugins/vis_type_table_new/public/components/table_vis_component.tsx new file mode 100644 index 000000000000..e24784d9eb1a --- /dev/null +++ b/src/plugins/vis_type_table_new/public/components/table_vis_component.tsx @@ -0,0 +1,142 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useCallback, useMemo } from 'react'; +import { orderBy } from 'lodash'; +import { EuiDataGridProps, EuiDataGrid, EuiDataGridSorting, EuiTitle } from '@elastic/eui'; + +import { IInterpreterRenderHandlers } from 'src/plugins/expressions'; +import { Table } from '../table_vis_response_handler'; +import { TableVisConfig, ColumnWidth, SortColumn, TableUiState } from '../types'; +import { getDataGridColumns } from './table_vis_grid_columns'; +import { usePagination } from '../utils'; +import { convertToFormattedData } from '../utils/convert_to_formatted_data'; +import { TableVisControl } from './table_vis_control'; + +interface TableVisComponentProps { + title?: string; + table: Table; + visConfig: TableVisConfig; + event: IInterpreterRenderHandlers['event']; + uiState: TableUiState; +} + +export const TableVisComponent = ({ + title, + table, + visConfig, + event, + uiState, +}: TableVisComponentProps) => { + const { formattedRows: rows, formattedColumns: columns } = convertToFormattedData( + table, + visConfig + ); + + const pagination = usePagination(visConfig, rows.length); + + const sortedRows = useMemo(() => { + return uiState.sort?.colIndex && uiState.sort.direction + ? orderBy(rows, columns[uiState.sort.colIndex]?.id, uiState.sort.direction) + : rows; + }, [columns, rows, uiState]); + + const renderCellValue = useMemo(() => { + return (({ rowIndex, columnId }) => { + const rawContent = sortedRows[rowIndex][columnId]; + const colIndex = columns.findIndex((col) => col.id === columnId); + const column = columns[colIndex]; + // use formatter to format raw content + // this can format date and percentage data + const formattedContent = column.formatter.convert(rawContent, 'text'); + return sortedRows.hasOwnProperty(rowIndex) ? formattedContent || null : null; + }) as EuiDataGridProps['renderCellValue']; + }, [sortedRows, columns]); + + const dataGridColumns = getDataGridColumns(sortedRows, columns, table, event, uiState.width); + + const sortedColumns = useMemo(() => { + return uiState.sort?.colIndex && uiState.sort.direction + ? [{ id: dataGridColumns[uiState.sort.colIndex]?.id, direction: uiState.sort.direction }] + : []; + }, [dataGridColumns, uiState]); + + const onSort = useCallback( + (sortingCols: EuiDataGridSorting['columns'] | []) => { + const nextSortValue = sortingCols[sortingCols.length - 1]; + const nextSort: SortColumn = + sortingCols.length > 0 + ? { + colIndex: dataGridColumns.findIndex((col) => col.id === nextSortValue?.id), + direction: nextSortValue.direction, + } + : { + colIndex: null, + direction: null, + }; + uiState.setSort(nextSort); + return nextSort; + }, + [dataGridColumns, uiState] + ); + + const onColumnResize: EuiDataGridProps['onColumnResize'] = useCallback( + ({ columnId, width }) => { + const curWidth: ColumnWidth[] = uiState.width; + const nextWidth = [...curWidth]; + const nextColIndex = columns.findIndex((col) => col.id === columnId); + const curColIndex = curWidth.findIndex((col) => col.colIndex === nextColIndex); + const nextColWidth = { colIndex: nextColIndex, width }; + + // if updated column index is not found, then add it to nextWidth + // else reset it in nextWidth + if (curColIndex < 0) nextWidth.push(nextColWidth); + else nextWidth[curColIndex] = nextColWidth; + + // update uiState.width + uiState.setWidth(nextWidth); + }, + [columns, uiState] + ); + + const ariaLabel = title || visConfig.title || 'tableVis'; + + return ( + <> + {title && ( + +

{title}

+
+ )} + id), + setVisibleColumns: () => {}, + }} + rowCount={rows.length} + renderCellValue={renderCellValue} + sorting={{ columns: sortedColumns, onSort }} + onColumnResize={onColumnResize} + pagination={pagination} + gridStyle={{ + border: 'horizontal', + header: 'underline', + }} + minSizeForControls={1} + toolbarVisibility={{ + showColumnSelector: false, + showSortSelector: false, + showFullScreenSelector: false, + showStyleSelector: false, + additionalControls: ( + + ), + }} + /> + + ); +}; diff --git a/src/plugins/vis_type_table_new/public/components/table_vis_component_group.tsx b/src/plugins/vis_type_table_new/public/components/table_vis_component_group.tsx new file mode 100644 index 000000000000..633b9d2230bd --- /dev/null +++ b/src/plugins/vis_type_table_new/public/components/table_vis_component_group.tsx @@ -0,0 +1,38 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { memo } from 'react'; + +import { IInterpreterRenderHandlers } from 'src/plugins/expressions'; +import { TableGroup } from '../table_vis_response_handler'; +import { TableVisConfig, TableUiState } from '../types'; +import { TableVisComponent } from './table_vis_component'; + +interface TableVisGroupComponentProps { + tableGroups: TableGroup[]; + visConfig: TableVisConfig; + event: IInterpreterRenderHandlers['event']; + uiState: TableUiState; +} + +export const TableVisComponentGroup = memo( + ({ tableGroups, visConfig, event, uiState }: TableVisGroupComponentProps) => { + return ( + <> + {tableGroups.map(({ tables, title }) => ( +
+ +
+ ))} + + ); + } +); diff --git a/src/plugins/vis_type_table_new/public/components/table_vis_control.tsx b/src/plugins/vis_type_table_new/public/components/table_vis_control.tsx new file mode 100644 index 000000000000..26b51c9cc85b --- /dev/null +++ b/src/plugins/vis_type_table_new/public/components/table_vis_control.tsx @@ -0,0 +1,55 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import { EuiPopover, EuiButtonEmpty, EuiContextMenuPanel, EuiContextMenuItem } from '@elastic/eui'; +import { OpenSearchDashboardsDatatableRow } from 'src/plugins/expressions'; +import { CoreStart } from 'opensearch-dashboards/public'; +import { exportAsCsv } from '../utils/convert_to_csv_data'; +import { FormattedColumn } from '../types'; +import { useOpenSearchDashboards } from '../../../../../src/plugins/opensearch_dashboards_react/public'; + +interface TableVisControlProps { + filename?: string; + rows: OpenSearchDashboardsDatatableRow[]; + columns: FormattedColumn[]; +} + +export const TableVisControl = (props: TableVisControlProps) => { + const { + services: { uiSettings }, + } = useOpenSearchDashboards(); + const [isPopoverOpen, setPopover] = useState(false); + + return ( + setPopover((open) => !open)} /> + } + isOpen={isPopoverOpen} + closePopover={() => setPopover(false)} + panelPaddingSize="none" + > + exportAsCsv(false, { ...props, uiSettings })} + > + Raw + , + exportAsCsv(true, { ...props, uiSettings })} + > + Formatted + , + ]} + /> + + ); +}; diff --git a/src/plugins/vis_type_table_new/public/components/table_vis_grid_columns.tsx b/src/plugins/vis_type_table_new/public/components/table_vis_grid_columns.tsx new file mode 100644 index 000000000000..ba204ea6ae33 --- /dev/null +++ b/src/plugins/vis_type_table_new/public/components/table_vis_grid_columns.tsx @@ -0,0 +1,148 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { i18n } from '@osd/i18n'; +import { EuiDataGridColumn, EuiDataGridColumnCellActionProps } from '@elastic/eui'; +import { IInterpreterRenderHandlers } from 'src/plugins/expressions'; +import { OpenSearchDashboardsDatatableRow } from 'src/plugins/expressions'; +import { Table } from '../table_vis_response_handler'; +import { ColumnWidth, FormattedColumn } from '../types'; + +export const getDataGridColumns = ( + rows: OpenSearchDashboardsDatatableRow[], + cols: FormattedColumn[], + table: Table, + event: IInterpreterRenderHandlers['event'], + columnsWidth: ColumnWidth[] +) => { + const filterBucket = (rowIndex: number, columnIndex: number, negate: boolean) => { + const foramttedColumnId = cols[columnIndex].id; + const rawColumnIndex = table.columns.findIndex((col) => col.id === foramttedColumnId); + event({ + name: 'filterBucket', + data: { + data: [ + { + table: { + columns: table.columns, + rows, + }, + row: rowIndex, + column: rawColumnIndex, + }, + ], + negate, + }, + }); + }; + + return cols.map((col, colIndex) => { + // const cellActions = col.filterable + // ? [ + // ({ rowIndex, columnId, Component, closePopover }: EuiDataGridColumnCellActionProps) => { + // const filterValue = rows[rowIndex][columnId]; + // const filterContent = col.formatter?.convert(filterValue); + + // const filterForValueText = i18n.translate( + // 'visTypeTableNew.tableVisFilter.filterForValue', + // { + // defaultMessage: 'Filter for value', + // } + // ); + // const filterForValueLabel = i18n.translate( + // 'visTypeTableNew.tableVisFilter.filterForValueLabel', + // { + // defaultMessage: 'Filter for value: {filterContent}', + // values: { + // filterContent, + // }, + // } + // ); + + // return ( + // filterValue != null && ( + // { + // filterBucket(rowIndex, colIndex, false); + // closePopover(); + // }} + // iconType="plusInCircle" + // aria-label={filterForValueLabel} + // data-test-subj="filterForValue" + // > + // {filterForValueText} + // + // ) + // ); + // }, + // ({ rowIndex, columnId, Component, closePopover }: EuiDataGridColumnCellActionProps) => { + // const filterValue = rows[rowIndex][columnId]; + // const filterContent = col.formatter?.convert(filterValue); + + // const filterOutValueText = i18n.translate( + // 'visTypeTableNew.tableVisFilter.filterOutValue', + // { + // defaultMessage: 'Filter out value', + // } + // ); + // const filterOutValueLabel = i18n.translate( + // 'visTypeTableNew.tableVisFilter.filterOutValueLabel', + // { + // defaultMessage: 'Filter out value: {filterContent}', + // values: { + // filterContent, + // }, + // } + // ); + + // return ( + // filterValue != null && ( + // { + // filterBucket(rowIndex, colIndex, true); + // closePopover(); + // }} + // iconType="minusInCircle" + // aria-label={filterOutValueLabel} + // data-test-subj="filterOutValue" + // > + // {filterOutValueText} + // + // ) + // ); + // }, + // ] + // : undefined; + + const initialWidth = columnsWidth.find((c) => c.colIndex === colIndex); + + const dataGridColumn: EuiDataGridColumn = { + id: col.id, + display: col.title, + displayAsText: col.title, + actions: { + showHide: false, + showMoveLeft: false, + showMoveRight: false, + showSortAsc: { + label: i18n.translate('visTypeTableNew.tableVisSort.ascSortLabel', { + defaultMessage: 'Sort asc', + }), + }, + showSortDesc: { + label: i18n.translate('visTypeTableNew.tableVisSort.descSortLabel', { + defaultMessage: 'Sort desc', + }), + }, + }, + // cellActions, + }; + if (initialWidth) { + dataGridColumn.initialWidth = initialWidth.width; + } + return dataGridColumn; + }); +}; diff --git a/src/plugins/vis_type_table_new/public/index.ts b/src/plugins/vis_type_table_new/public/index.ts new file mode 100644 index 000000000000..4ed30b71eeaa --- /dev/null +++ b/src/plugins/vis_type_table_new/public/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +// import { PluginInitializerContext } from 'opensearch-dashboards/public'; +import { TableVisPlugin as Plugin } from './plugin'; + +export function plugin() { + return new Plugin(); +} +/* Public Types */ +export { TableVisExpressionFunctionDefinition } from './table_vis_fn'; diff --git a/src/plugins/vis_type_table_new/public/plugin.ts b/src/plugins/vis_type_table_new/public/plugin.ts new file mode 100644 index 000000000000..9cc96c3e9895 --- /dev/null +++ b/src/plugins/vis_type_table_new/public/plugin.ts @@ -0,0 +1,36 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreSetup, CoreStart, Plugin } from 'opensearch-dashboards/public'; +import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public'; + +import { createTableVisFn } from './table_vis_fn'; +import { DataPublicPluginStart } from '../../data/public'; +import { setFormatService } from './services'; +import { getTableVisRenderer } from './table_vis_renderer'; + +export interface TableVisPluginSetupDependencies { + expressions: ReturnType; +} + +export interface TableVisPluginStartDependencies { + data: DataPublicPluginStart; +} + +const setupTableVis = async (core: CoreSetup, { expressions }: TableVisPluginSetupDependencies) => { + const [coreStart] = await core.getStartServices(); + expressions.registerFunction(createTableVisFn); + expressions.registerRenderer(getTableVisRenderer(coreStart)); +}; + +export class TableVisPlugin implements Plugin { + public async setup(core: CoreSetup, dependencies: TableVisPluginSetupDependencies) { + setupTableVis(core, dependencies); + } + + public start(core: CoreStart, { data }: TableVisPluginStartDependencies) { + setFormatService(data.fieldFormats); + } +} diff --git a/src/plugins/vis_type_table_new/public/services.ts b/src/plugins/vis_type_table_new/public/services.ts new file mode 100644 index 000000000000..f8ca4b574307 --- /dev/null +++ b/src/plugins/vis_type_table_new/public/services.ts @@ -0,0 +1,11 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { createGetterSetter } from '../../opensearch_dashboards_utils/public'; +import { DataPublicPluginStart } from '../../data/public'; + +export const [getFormatService, setFormatService] = createGetterSetter< + DataPublicPluginStart['fieldFormats'] +>('table data.fieldFormats'); diff --git a/src/plugins/vis_type_table_new/public/table_vis_fn.ts b/src/plugins/vis_type_table_new/public/table_vis_fn.ts new file mode 100644 index 000000000000..ec9eafc344af --- /dev/null +++ b/src/plugins/vis_type_table_new/public/table_vis_fn.ts @@ -0,0 +1,65 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { tableVisResponseHandler, TableContext } from './table_vis_response_handler'; +import { + ExpressionFunctionDefinition, + OpenSearchDashboardsDatatable, + Render, +} from '../../expressions/public'; +import { TableVisConfig } from './types'; + +export type Input = OpenSearchDashboardsDatatable; + +interface Arguments { + visConfig: string | null; +} + +export interface TableVisRenderValue { + visData: TableContext; + visType: 'table'; + visConfig: TableVisConfig; +} + +export type TableVisExpressionFunctionDefinition = ExpressionFunctionDefinition< + 'opensearch_dashboards_table_new', + Input, + Arguments, + Render +>; + +export const createTableVisFn = (): TableVisExpressionFunctionDefinition => ({ + name: 'opensearch_dashboards_table_new', + type: 'render', + inputTypes: ['opensearch_dashboards_datatable'], + help: i18n.translate('visTypeTableNew.function.help', { + defaultMessage: 'Table visualization', + }), + args: { + visConfig: { + types: ['string', 'null'], + default: '"{}"', + help: '', + }, + }, + fn(input, args) { + const visConfig = args.visConfig && JSON.parse(args.visConfig); + const convertedData = tableVisResponseHandler(input, visConfig); + + return { + type: 'render', + as: 'table_vis', + value: { + visData: convertedData, + visType: 'table', + visConfig, + }, + params: { + listenOnChange: true, + }, + }; + }, +}); diff --git a/src/plugins/vis_type_table_new/public/table_vis_renderer.tsx b/src/plugins/vis_type_table_new/public/table_vis_renderer.tsx new file mode 100644 index 000000000000..8e467112528d --- /dev/null +++ b/src/plugins/vis_type_table_new/public/table_vis_renderer.tsx @@ -0,0 +1,36 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; + +import { CoreStart } from 'opensearch-dashboards/public'; +import { VisualizationContainer } from '../../visualizations/public'; +import { ExpressionRenderDefinition } from '../../expressions/common/expression_renderers'; +import { TableVisRenderValue } from './table_vis_fn'; +import { TableVisApp } from './components/table_vis_app'; + +export const getTableVisRenderer: ( + core: CoreStart +) => ExpressionRenderDefinition = (core) => ({ + name: 'table_vis', + displayName: 'table visualization', + reuseDomNode: true, + render: async (domNode, { visData, visConfig }, handlers) => { + handlers.onDestroy(() => { + unmountComponentAtNode(domNode); + }); + + const showNoResult = visData.table + ? visData.table.rows.length === 0 + : visData.tableGroups?.length === 0; + render( + + + , + domNode + ); + }, +}); diff --git a/src/plugins/vis_type_table_new/public/table_vis_response_handler.ts b/src/plugins/vis_type_table_new/public/table_vis_response_handler.ts new file mode 100644 index 000000000000..b1d41edfff8b --- /dev/null +++ b/src/plugins/vis_type_table_new/public/table_vis_response_handler.ts @@ -0,0 +1,112 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { getFormatService } from './services'; +import { OpenSearchDashboardsDatatable } from '../../expressions/public'; +import { TableVisConfig } from './types'; + +export interface Table { + columns: OpenSearchDashboardsDatatable['columns']; + rows: OpenSearchDashboardsDatatable['rows']; +} + +export interface TableGroup { + table: OpenSearchDashboardsDatatable; + tables: Table[]; + title: string; + name: string; + key: any; + column: number; + row: number; +} + +export interface TableContext { + table?: Table; + tableGroups: TableGroup[]; + direction?: 'row' | 'column'; +} + +export function tableVisResponseHandler( + input: OpenSearchDashboardsDatatable, + config: TableVisConfig +): TableContext { + let table: Table | undefined; + const tableGroups: TableGroup[] = []; + let direction: TableContext['direction']; + + const split = config.splitColumn || config.splitRow; + + if (split) { + direction = config.splitRow ? 'row' : 'column'; + const splitColumnIndex = split[0].accessor; + const splitColumnFormatter = getFormatService().deserialize(split[0].format); + const splitColumn = input.columns[splitColumnIndex]; + const splitMap: { [key: string]: number } = {}; + let splitIndex = 0; + + input.rows.forEach((row, rowIndex) => { + const splitValue: any = row[splitColumn.id]; + + if (!splitMap.hasOwnProperty(splitValue as any)) { + (splitMap as any)[splitValue] = splitIndex++; + const tableGroup: TableGroup = { + title: `${splitColumnFormatter.convert(splitValue)}: ${splitColumn.name}`, + name: splitColumn.name, + key: splitValue, + column: splitColumnIndex, + row: rowIndex, + table: input, + tables: [], + }; + + tableGroup.tables.push({ + columns: input.columns, + rows: [], + }); + + tableGroups.push(tableGroup); + } + + const tableIndex = (splitMap as any)[splitValue]; + (tableGroups[tableIndex] as any).tables[0].rows.push(row); + }); + } else { + table = { + columns: input.columns, + rows: input.rows, + }; + } + + return { + table, + tableGroups, + direction, + }; +} diff --git a/src/plugins/vis_type_table_new/public/types.ts b/src/plugins/vis_type_table_new/public/types.ts new file mode 100644 index 000000000000..0c5a9f9955e0 --- /dev/null +++ b/src/plugins/vis_type_table_new/public/types.ts @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { SchemaConfig } from 'src/plugins/visualizations/public'; +import { IFieldFormat } from 'src/plugins/data/public'; + +export interface TableVisConfig extends TableVisParams { + title: string; + metrics: SchemaConfig[]; + buckets: SchemaConfig[]; + splitRow?: SchemaConfig[]; + splitColumn?: SchemaConfig[]; +} + +export interface TableVisParams { + perPage: number | ''; + showPartialRows: boolean; + showMetricsAtAllLevels: boolean; +} + +export interface FormattedColumn { + id: string; + title: string; + formatter: IFieldFormat; + filterable: boolean; +} + +export interface ColumnWidth { + colIndex: number; + width: number; +} + +export interface SortColumn { + colIndex: number | null; + direction: 'asc' | 'desc' | null; +} + +export interface TableUiState { + sort: SortColumn; + setSort: (sort: SortColumn) => void; + width: ColumnWidth[]; + setWidth: (columnsWidth: ColumnWidth[]) => void; +} diff --git a/src/plugins/vis_type_table_new/public/utils/convert_to_csv_data.ts b/src/plugins/vis_type_table_new/public/utils/convert_to_csv_data.ts new file mode 100644 index 000000000000..2c37df1aa3d5 --- /dev/null +++ b/src/plugins/vis_type_table_new/public/utils/convert_to_csv_data.ts @@ -0,0 +1,85 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { isObject } from 'lodash'; +// @ts-ignore +import { saveAs } from '@elastic/filesaver'; +import { CoreStart } from 'opensearch-dashboards/public'; +import { CSV_SEPARATOR_SETTING, CSV_QUOTE_VALUES_SETTING } from '../../../share/public'; +import { OpenSearchDashboardsDatatable } from '../../../expressions/public'; +import { FormattedColumn } from '../types'; + +const nonAlphaNumRE = /[^a-zA-Z0-9]/; +const allDoubleQuoteRE = /"/g; + +interface CSVDataProps { + filename?: string; + rows: OpenSearchDashboardsDatatable['rows']; + columns: FormattedColumn[]; + uiSettings: CoreStart['uiSettings']; +} + +const toCsv = function (formatted: boolean, { rows, columns, uiSettings }: CSVDataProps) { + const separator = uiSettings.get(CSV_SEPARATOR_SETTING); + const quoteValues = uiSettings.get(CSV_QUOTE_VALUES_SETTING); + + function escape(val: any) { + if (!formatted && isObject(val)) val = val.valueOf(); + val = String(val); + if (quoteValues && nonAlphaNumRE.test(val)) { + val = '"' + val.replace(allDoubleQuoteRE, '""') + '"'; + } + return val; + } + + let csvRows: string[][] = []; + for (const row of rows) { + const rowArray = []; + for (const col of columns) { + const value = row[col.id]; + const formattedValue = + formatted && col.formatter ? escape(col.formatter.convert(value)) : escape(value); + rowArray.push(formattedValue); + } + csvRows = [...csvRows, rowArray]; + } + + // add the columns to the rows + csvRows.unshift(columns.map((col) => escape(col.title))); + + return csvRows.map((row) => row.join(separator) + '\r\n').join(''); +}; + +export const exportAsCsv = function (formatted: boolean, csvData: CSVDataProps) { + const csv = new Blob([toCsv(formatted, csvData)], { type: 'text/csv;charset=utf-8' }); + const type = formatted ? 'formatted' : 'raw'; + if (csvData.filename) saveAs(csv, `${csvData.filename}-${type}.csv`); + else saveAs(csv, `unsaved-${type}.csv`); +}; diff --git a/src/plugins/vis_type_table_new/public/utils/convert_to_formatted_data.ts b/src/plugins/vis_type_table_new/public/utils/convert_to_formatted_data.ts new file mode 100644 index 000000000000..cd997dfe5d5e --- /dev/null +++ b/src/plugins/vis_type_table_new/public/utils/convert_to_formatted_data.ts @@ -0,0 +1,68 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { OpenSearchDashboardsDatatableRow } from 'src/plugins/expressions'; +import { Table } from '../table_vis_response_handler'; +import { TableVisConfig } from '../types'; +import { getFormatService } from '../services'; +import { FormattedColumn } from '../types'; +export interface FormattedDataProps { + formattedRows: OpenSearchDashboardsDatatableRow[]; + formattedColumns: FormattedColumn[]; +} + +export const convertToFormattedData = ( + table: Table, + visConfig: TableVisConfig +): FormattedDataProps => { + const { buckets, metrics } = visConfig; + const formattedRows: OpenSearchDashboardsDatatableRow[] = table.rows; + const formattedColumns: FormattedColumn[] = table.columns + .map(function (col, i) { + const isBucket = buckets.find((bucket) => bucket.accessor === i); + const dimension = isBucket || metrics.find((metric) => metric.accessor === i); + + if (!dimension) return undefined; + + const formatter = getFormatService().deserialize(dimension.format); + + const formattedColumn: FormattedColumn = { + id: col.id, + title: col.name, + formatter, + filterable: !!isBucket, + }; + + return formattedColumn; + }) + .filter((column): column is FormattedColumn => !!column); + + return { formattedRows, formattedColumns }; +}; diff --git a/src/plugins/vis_type_table_new/public/utils/index.ts b/src/plugins/vis_type_table_new/public/utils/index.ts new file mode 100644 index 000000000000..1fd0e3f1e0fd --- /dev/null +++ b/src/plugins/vis_type_table_new/public/utils/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './convert_to_csv_data'; +export * from './convert_to_formatted_data'; +export * from './use_pagination'; diff --git a/src/plugins/vis_type_table_new/public/utils/use_pagination.ts b/src/plugins/vis_type_table_new/public/utils/use_pagination.ts new file mode 100644 index 000000000000..45dbed2c0da8 --- /dev/null +++ b/src/plugins/vis_type_table_new/public/utils/use_pagination.ts @@ -0,0 +1,39 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { TableVisConfig } from '../types'; + +export const usePagination = (visConfig: TableVisConfig, nRow: number) => { + const [pagination, setPagination] = useState({ + pageIndex: 0, + pageSize: visConfig.perPage || 10, + }); + const onChangeItemsPerPage = useCallback( + (pageSize) => setPagination((p) => ({ ...p, pageSize, pageIndex: 0 })), + [setPagination] + ); + const onChangePage = useCallback((pageIndex) => setPagination((p) => ({ ...p, pageIndex })), [ + setPagination, + ]); + + useEffect(() => { + const perPage = visConfig.perPage || 10; + const maxiPageIndex = Math.ceil(nRow / perPage) - 1; + setPagination((p) => ({ + pageIndex: p.pageIndex > maxiPageIndex ? maxiPageIndex : p.pageIndex, + pageSize: perPage, + })); + }, [nRow, visConfig.perPage]); + + return useMemo( + () => ({ + ...pagination, + onChangeItemsPerPage, + onChangePage, + }), + [pagination, onChangeItemsPerPage, onChangePage] + ); +}; From 812f1131f7f9742e3021b49fd206c7559e1b558f Mon Sep 17 00:00:00 2001 From: himsgupta1122 <115103225+himsgupta1122@users.noreply.github.com> Date: Thu, 3 Nov 2022 18:25:46 -0700 Subject: [PATCH 11/25] Security-CVEs fixes guidelines (#2674) * Security-CVEs fixes guidelines Signed-off-by: himsgupta1122 * styling Signed-off-by: himsgupta1122 * add example Signed-off-by: himsgupta1122 * add documention Signed-off-by: himsgupta1122 Signed-off-by: himsgupta1122 --- SECURITY.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 0b85ca04ed26..f450e11235ba 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,3 +1,27 @@ ## Reporting a Vulnerability -If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/) or directly via email to aws-security@amazon.com. Please do **not** create a public GitHub issue. \ No newline at end of file +- If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/) or directly via email to aws-security@amazon.com. Please do **not** create a public GitHub issue. + +- For Security-CVE related fix - + - For direct dependency - Use ```yarn upgrade package``` to update the package and in order to enforce as sub-deps please add nested-dep step2. + + - For nested dependency/sub-deps - In order to enforce package above Vx.y.z, we can add version in the resolutions [section](https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/) for all the package sub-deps or specific package sub-dep. For more on version updates please see +[Why](https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/#toc-why-would-you-want-to-do-this) and [How](https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/#toc-how-to-use-it) to upgrade. + - To add the CVEs fix to previous versions, add label ex: backport 1.x. + + ``` + Example: foobar@1.x vulnerable package and 1.y is the fix + step 1: + For direct dependency checks: + run: yarn upgrade foobar@1.y to update the package.json + and yarn install to update the yarn.lock file + Step 2. + Check for sub deps foobar in other package. + If foobar@1.x exists for subdeps in yarn.lock file + Then edit the package.json file and add **/foobar@1.y in resolution section as shown below to enforce the 1.y. + 'resolutions': { "**/foobar": "^1.y", + "**/foo": "^2.x" , + "**/bar": "^3.k"} + Then run: yarn install for updating yarn.lock file + + \ No newline at end of file From d93ea2ee981a9d5dd8102f4f6af31198ce9ba20c Mon Sep 17 00:00:00 2001 From: Kristen Tian <105667444+kristenTian@users.noreply.github.com> Date: Fri, 4 Nov 2022 00:47:01 -0700 Subject: [PATCH 12/25] [MD] Update default audit log path (#2793) - Fix the /tmp path issue seen on windows platform. - Change audit log to disable by default. Signed-off-by: Kristen Tian Signed-off-by: Kristen Tian --- CHANGELOG.md | 1 + src/plugins/data_source/README.md | 8 ++++---- src/plugins/data_source/audit_config.ts | 4 +++- src/plugins/data_source/config.ts | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2ad560973bd..47d1e92c4e39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Removed Leftover X Pack references ([#2638](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2638)) - Removes Add Integration button ([#2723](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2723)) - Change geckodriver version to make consistency ([#2772](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2772)) +- [Multi DataSource] Update default audit log path ([#2793](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2793)) ### 🚞 Infrastructure diff --git a/src/plugins/data_source/README.md b/src/plugins/data_source/README.md index a76e9a1fb5a0..ca212f4ded7f 100755 --- a/src/plugins/data_source/README.md +++ b/src/plugins/data_source/README.md @@ -11,15 +11,15 @@ Update the following configuration in the `opensearch_dashboards.yml` file to ap 1. The dataSource plugin is disabled by default; to enable it: `data_source.enabled: true` -2. The audit trail is enabled by default for logging the access to data source; to disable it: - `data_source.audit.enabled: false` +2. The audit trail is disabled by default for logging the access to data source; to disable it: + `data_source.audit.enabled: true` -- Current auditor configuration: +- Default auditor configuration: ```yml data_source.audit.appender.kind: 'file' data_source.audit.appender.layout.kind: 'pattern' -data_source.audit.appender.path: '/tmp/opensearch-dashboards-data-source-audit.log' +data_source.audit.appender.path: '/opensearch-dashboards-data-source-audit.log' ``` 3. The default encryption-related configuration parameters are: diff --git a/src/plugins/data_source/audit_config.ts b/src/plugins/data_source/audit_config.ts index d8c99fbfa846..ec898ff5441e 100644 --- a/src/plugins/data_source/audit_config.ts +++ b/src/plugins/data_source/audit_config.ts @@ -4,6 +4,8 @@ */ import { schema } from '@osd/config-schema'; +import os from 'os'; +import path from 'path'; // eslint-disable-next-line @osd/eslint/no-restricted-paths import { DateConversion } from '../../../src/core/server/logging/layouts/conversions'; @@ -36,7 +38,7 @@ export const fileAppenderSchema = schema.object( kind: 'pattern', highlight: true, }, - path: '/tmp/opensearch-dashboards-data-source-audit.log', + path: path.join(os.tmpdir(), 'opensearch-dashboards-data-source-audit.log'), }, } ); diff --git a/src/plugins/data_source/config.ts b/src/plugins/data_source/config.ts index f2fd79fade9a..1fc4e00c3e23 100644 --- a/src/plugins/data_source/config.ts +++ b/src/plugins/data_source/config.ts @@ -34,7 +34,7 @@ export const configSchema = schema.object({ size: schema.number({ defaultValue: 5 }), }), audit: schema.object({ - enabled: schema.boolean({ defaultValue: true }), + enabled: schema.boolean({ defaultValue: false }), appender: fileAppenderSchema, }), }); From 2e16de11438bd0e1cc261452fb750b64f927a9f2 Mon Sep 17 00:00:00 2001 From: Josh Romero Date: Fri, 4 Nov 2022 10:40:59 -0700 Subject: [PATCH 13/25] [Vis Builder] Add field summary popovers (#2682) * [Vis Builder] Add field summary popovers Much of the functionality was ported from `Discover`, but largely refactored. * Add utilities to get sampled hit summaries by field * Add popover summaries * Slight refactor of special `Count` pseudofield * Use observable subscription to update sampled hits Fixes #950 Signed-off-by: Josh Romero * [Vis Builder] Add additional unit tests Signed-off-by: Josh Romero * [VisBuilder] Update naming of summary field components Signed-off-by: Josh Romero * [VisBuilder] Avoid prop passing by extracting custom hooks - refactor meta field identification Signed-off-by: Josh Romero * [VisBuilder] Add TODOs with issue links, fix test ID Restores previous test ID for count field button Signed-off-by: Josh Romero Signed-off-by: Josh Romero --- CHANGELOG.md | 1 + .../{field_selector_field.scss => field.scss} | 7 +- .../components/data_tab/field.test.tsx | 46 +++ .../application/components/data_tab/field.tsx | 113 ++++++++ .../components/data_tab/field_bucket.scss | 4 + .../components/data_tab/field_bucket.tsx | 110 +++++++ .../data_tab/field_details.test.tsx | 155 ++++++++++ .../components/data_tab/field_details.tsx | 92 ++++++ .../data_tab/field_selector.test.tsx | 82 ++++++ .../components/data_tab/field_selector.tsx | 132 +++++---- .../data_tab/field_selector_field.tsx | 86 ------ .../application/components/data_tab/types.ts | 22 ++ .../data_tab/utils/field_calculator.test.ts | 268 ++++++++++++++++++ .../data_tab/utils/field_calculator.ts | 124 ++++++++ .../data_tab/utils/get_field_details.ts | 57 ++++ .../components/data_tab/utils/index.ts | 1 + .../utils/drag_drop/drag_drop_context.tsx | 2 +- .../application/utils/drag_drop/index.ts | 1 + .../public/application/utils/use/index.ts | 4 +- .../utils/use/use_on_add_filter.ts | 35 +++ .../application/utils/use/use_sample_hits.ts | 80 ++++++ 21 files changed, 1276 insertions(+), 146 deletions(-) rename src/plugins/vis_builder/public/application/components/data_tab/{field_selector_field.scss => field.scss} (83%) create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/field.test.tsx create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/field.tsx create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/field_bucket.scss create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/field_bucket.tsx create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/field_details.test.tsx create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/field_details.tsx create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/field_selector.test.tsx delete mode 100644 src/plugins/vis_builder/public/application/components/data_tab/field_selector_field.tsx create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/types.ts create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/utils/field_calculator.test.ts create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/utils/field_calculator.ts create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/utils/get_field_details.ts create mode 100644 src/plugins/vis_builder/public/application/utils/use/use_on_add_filter.ts create mode 100644 src/plugins/vis_builder/public/application/utils/use/use_sample_hits.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 47d1e92c4e39..be347e38a846 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Save Object Aggregation View] Add extension point in saved object management to register namespaces and show filter ([#2656](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2656)) - [Save Object Aggregation View] Fix for export all after scroll count response changed in PR#2656 ([#2696](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2696)) - [Vis Builder] Add an experimental table visualization in vis builder ([#2705](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2705)) +- [Vis Builder] Add field summary popovers ([#2682](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2682)) ### 🐛 Bug Fixes diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field_selector_field.scss b/src/plugins/vis_builder/public/application/components/data_tab/field.scss similarity index 83% rename from src/plugins/vis_builder/public/application/components/data_tab/field_selector_field.scss rename to src/plugins/vis_builder/public/application/components/data_tab/field.scss index c129f7a997a1..2c4a96c6ec56 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/field_selector_field.scss +++ b/src/plugins/vis_builder/public/application/components/data_tab/field.scss @@ -2,7 +2,7 @@ * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ -.vbFieldSelectorField { +.vbFieldButton { @include euiBottomShadowSmall; background-color: $euiColorEmptyShade; @@ -26,3 +26,8 @@ height: 100%; } } + +.vbItem__fieldPopoverPanel { + min-width: 260px; + max-width: 300px; +} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field.test.tsx b/src/plugins/vis_builder/public/application/components/data_tab/field.test.tsx new file mode 100644 index 000000000000..6aed9deb159e --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/field.test.tsx @@ -0,0 +1,46 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; + +import { IndexPatternField } from '../../../../../data/public'; + +import { DraggableFieldButton } from './field'; + +describe('visBuilder field', function () { + describe('DraggableFieldButton', () => { + it('should render normal fields without a dragValue specified', async () => { + const props = { + field: new IndexPatternField( + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + 'bytes' + ), + }; + render(); + + const button = screen.getByTestId('field-bytes-showDetails'); + + expect(button).toBeDefined(); + }); + + // TODO: it('should allow specified dragValue to override the field name'); + + // TODO: it('should make dots wrappable'); + + // TODO: it('should use a non-scripted FieldIcon by default'); + }); + + // TODO: describe('Field', function () { }); +}); diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field.tsx b/src/plugins/vis_builder/public/application/components/data_tab/field.tsx new file mode 100644 index 000000000000..287c6aed621c --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/field.tsx @@ -0,0 +1,113 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState } from 'react'; +import { EuiPopover } from '@elastic/eui'; + +import { IndexPatternField } from '../../../../../data/public'; +import { + FieldButton, + FieldButtonProps, + FieldIcon, +} from '../../../../../opensearch_dashboards_react/public'; + +import { COUNT_FIELD, useDrag } from '../../utils/drag_drop'; +import { FieldDetailsView } from './field_details'; +import { FieldDetails } from './types'; +import './field.scss'; + +export interface FieldProps { + field: IndexPatternField; + getDetails: (field) => FieldDetails; +} + +// TODO: Add field sections (Available fields, popular fields from src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx) +export const Field = ({ field, getDetails }: FieldProps) => { + const [infoIsOpen, setOpen] = useState(false); + + function togglePopover() { + setOpen(!infoIsOpen); + } + + return ( + } + isOpen={infoIsOpen} + closePopover={() => setOpen(false)} + anchorPosition="rightUp" + panelClassName="vbItem__fieldPopoverPanel" + // TODO: make reposition on scroll actually work: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2782 + repositionOnScroll + data-test-subj="field-popover" + > + {infoIsOpen && } + + ); +}; + +export interface DraggableFieldButtonProps extends Partial { + dragValue?: IndexPatternField['name'] | null | typeof COUNT_FIELD; + field: Partial & Pick; +} + +export const DraggableFieldButton = ({ dragValue, field, ...rest }: DraggableFieldButtonProps) => { + const { name, displayName, type, scripted = false } = field; + const [dragProps] = useDrag({ + namespace: 'field-data', + value: dragValue ?? name, + }); + + function wrapOnDot(str: string) { + // u200B is a non-width white-space character, which allows + // the browser to efficiently word-wrap right after the dot + // without us having to draw a lot of extra DOM elements, etc + return str.replace(/\./g, '.\u200B'); + } + + const defaultIcon = ; + + const defaultFieldName = ( + + {wrapOnDot(displayName)} + + ); + + const defaultProps = { + className: 'vbFieldButton', + dataTestSubj: `field-${name}-showDetails`, + fieldIcon: defaultIcon, + fieldName: defaultFieldName, + onClick: () => {}, + }; + + return ; +}; diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field_bucket.scss b/src/plugins/vis_builder/public/application/components/data_tab/field_bucket.scss new file mode 100644 index 000000000000..50951d850a62 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/field_bucket.scss @@ -0,0 +1,4 @@ +.vbFieldDetails__barContainer { + // Constrains value to the flex item, and allows for truncation when necessary + min-width: 0; +} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field_bucket.tsx b/src/plugins/vis_builder/public/application/components/data_tab/field_bucket.tsx new file mode 100644 index 000000000000..1a45857a6550 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/field_bucket.tsx @@ -0,0 +1,110 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { + EuiText, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiProgress, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; + +import { IndexPatternField } from '../../../../../data/public'; + +import { Bucket } from './types'; +import './field_bucket.scss'; +import { useOnAddFilter } from '../../utils/use'; + +interface FieldBucketProps { + bucket: Bucket; + field: IndexPatternField; +} + +export function FieldBucket({ bucket, field }: FieldBucketProps) { + const { count, display, percent, value } = bucket; + const { filterable: isFilterableField, name: fieldName } = field; + + const onAddFilter = useOnAddFilter(); + + const emptyText = i18n.translate('visBuilder.fieldSelector.detailsView.emptyStringText', { + // We need this to communicate to users when a top value is actually an empty string + defaultMessage: 'Empty string', + }); + const addLabel = i18n.translate( + 'visBuilder.fieldSelector.detailsView.filterValueButtonAriaLabel', + { + defaultMessage: 'Filter for {fieldName}: "{value}"', + values: { fieldName, value }, + } + ); + const removeLabel = i18n.translate( + 'visBuilder.fieldSelector.detailsView.filterOutValueButtonAriaLabel', + { + defaultMessage: 'Filter out {fieldName}: "{value}"', + values: { fieldName, value }, + } + ); + + const displayValue = display || emptyText; + + return ( + <> + + + + + + {displayValue} + + + + + {percent.toFixed(1)}% + + + + + + {/* TODO: Should we have any explanation for non-filterable fields? */} + {isFilterableField && ( + +
+ onAddFilter(field, value, '+')} + aria-label={addLabel} + data-test-subj={`plus-${fieldName}-${value}`} + /> + onAddFilter(field, value, '-')} + aria-label={removeLabel} + data-test-subj={`minus-${fieldName}-${value}`} + /> +
+
+ )} +
+ + + ); +} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field_details.test.tsx b/src/plugins/vis_builder/public/application/components/data_tab/field_details.test.tsx new file mode 100644 index 000000000000..83a148b2f77b --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/field_details.test.tsx @@ -0,0 +1,155 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +// @ts-ignore +import { findTestSubject } from '@elastic/eui/lib/test'; +// @ts-ignore +import stubbedLogstashFields from 'fixtures/logstash_fields'; +// @ts-ignore +import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers'; + +import { IndexPatternField } from '../../../../../data/public'; + +import { FieldDetailsView } from './field_details'; + +const mockUseIndexPatterns = jest.fn(() => ({ selected: 'mockIndexPattern' })); +const mockUseOnAddFilter = jest.fn(); +jest.mock('../../utils/use', () => ({ + useIndexPatterns: jest.fn(() => mockUseIndexPatterns), + useOnAddFilter: jest.fn(() => mockUseOnAddFilter), +})); + +describe('visBuilder field details', function () { + const defaultDetails = { buckets: [], error: '', exists: 1, total: 1 }; + function mountComponent(field: IndexPatternField, props?: Record) { + const compProps = { details: defaultDetails, ...props, field }; + return mountWithIntl(); + } + + it('should render buckets if they exist', async function () { + const field = new IndexPatternField( + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + 'bytes' + ); + const buckets = [1, 2, 3].map((n) => ({ + display: `display-${n}`, + value: `value-${n}`, + percent: 25, + count: 100, + })); + const comp = mountComponent(field, { + details: { ...defaultDetails, buckets }, + }); + expect(findTestSubject(comp, 'fieldDetailsContainer').length).toBe(1); + expect(findTestSubject(comp, 'fieldDetailsError').length).toBe(0); + expect(findTestSubject(comp, 'fieldDetailsBucketsContainer').length).toBe(1); + expect(findTestSubject(comp, 'fieldDetailsBucketsContainer').children().length).toBe( + buckets.length + ); + expect(findTestSubject(comp, 'fieldDetailsExistsLink').length).toBe(1); + }); + + it('should only render buckets if they exist', async function () { + const field = new IndexPatternField( + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + 'bytes' + ); + const comp = mountComponent(field); + expect(findTestSubject(comp, 'fieldDetailsContainer').length).toBe(1); + expect(findTestSubject(comp, 'fieldDetailsError').length).toBe(0); + expect(findTestSubject(comp, 'fieldDetailsBucketsContainer').length).toBe(1); + expect(findTestSubject(comp, 'fieldDetailsBucketsContainer').children().length).toBe(0); + expect(findTestSubject(comp, 'fieldDetailsExistsLink').length).toBe(1); + }); + + it('should render a details error', async function () { + const field = new IndexPatternField( + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + 'bytes' + ); + const errText = 'Some error'; + const comp = mountComponent(field, { + details: { ...defaultDetails, error: errText }, + }); + expect(findTestSubject(comp, 'fieldDetailsContainer').length).toBe(1); + expect(findTestSubject(comp, 'fieldDetailsBucketsContainer').children().length).toBe(0); + expect(findTestSubject(comp, 'fieldDetailsError').length).toBe(1); + expect(findTestSubject(comp, 'fieldDetailsError').text()).toBe(errText); + expect(findTestSubject(comp, 'fieldDetailsExistsLink').length).toBe(0); + }); + + it('should not render an exists filter link for scripted fields', async function () { + const field = new IndexPatternField( + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: true, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + 'bytes' + ); + const comp = mountComponent(field); + expect(findTestSubject(comp, 'fieldDetailsContainer').length).toBe(1); + expect(findTestSubject(comp, 'fieldDetailsError').length).toBe(0); + expect(findTestSubject(comp, 'fieldDetailsExistsLink').length).toBe(0); + }); +}); diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field_details.tsx b/src/plugins/vis_builder/public/application/components/data_tab/field_details.tsx new file mode 100644 index 000000000000..cf6f4974bb18 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/field_details.tsx @@ -0,0 +1,92 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiLink, EuiPopoverFooter, EuiPopoverTitle, EuiText } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; + +import { IndexPatternField } from '../../../../../data/public'; + +import { useIndexPatterns, useOnAddFilter } from '../../utils/use'; +import { FieldBucket } from './field_bucket'; +import { Bucket, FieldDetails } from './types'; + +interface FieldDetailsProps { + field: IndexPatternField; + details: FieldDetails; +} + +export function FieldDetailsView({ field, details }: FieldDetailsProps) { + const { buckets, error, exists, total } = details; + + const onAddFilter = useOnAddFilter(); + const indexPattern = useIndexPatterns().selected; + + const { metaFields = [] } = indexPattern ?? {}; + const isMetaField = metaFields.includes(field.name); + const shouldAllowExistsFilter = !isMetaField && !field.scripted; + + const bucketsTitle = + buckets.length > 1 + ? i18n.translate('visBuilder.fieldSelector.detailsView.fieldTopValuesLabel', { + defaultMessage: 'Top {n} values', + values: { n: buckets.length }, + }) + : i18n.translate('visBuilder.fieldSelector.detailsView.fieldTopValueLabel', { + defaultMessage: 'Top value', + }); + const errorTitle = i18n.translate('visBuilder.fieldSelector.detailsView.fieldNoValuesLabel', { + defaultMessage: 'No values found', + }); + const existsIn = i18n.translate('visBuilder.fieldSelector.detailsView.fieldExistsIn', { + defaultMessage: 'Exists in {exists}', + values: { exists }, + }); + const totalRecords = i18n.translate('visBuilder.fieldSelector.detailsView.fieldTotalRecords', { + defaultMessage: '/ {total} records', + values: { total }, + }); + + const title = buckets.length ? bucketsTitle : errorTitle; + + return ( + <> + {title} +
+ {error ? ( + + {error} + + ) : ( +
+ {buckets.map((bucket: Bucket, idx: number) => ( + + ))} +
+ )} +
+ {!error && ( + + + {shouldAllowExistsFilter ? ( + onAddFilter('_exists_', field.name, '+')} + data-test-subj="fieldDetailsExistsLink" + > + {existsIn} + + ) : ( + <>{exists} + )}{' '} + {totalRecords} + + + )} + + ); +} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field_selector.test.tsx b/src/plugins/vis_builder/public/application/components/data_tab/field_selector.test.tsx new file mode 100644 index 000000000000..980cfb50c666 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/field_selector.test.tsx @@ -0,0 +1,82 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { fireEvent, render, screen } from '@testing-library/react'; +import { FilterManager, IndexPatternField } from '../../../../../data/public'; +import { FieldGroup } from './field_selector'; + +const mockUseIndexPatterns = jest.fn(() => ({ selected: 'mockIndexPattern' })); +const mockUseOnAddFilter = jest.fn(); +jest.mock('../../utils/use', () => ({ + useIndexPatterns: jest.fn(() => mockUseIndexPatterns), + useOnAddFilter: jest.fn(() => mockUseOnAddFilter), +})); + +const mockGetDetailsByField = jest.fn(() => ({ + buckets: [1, 2, 3].map((n) => ({ + display: `display-${n}`, + value: `value-${n}`, + percent: 25, + count: 100, + })), + error: '', + exists: 100, + total: 150, +})); + +const getFields = (name) => { + return new IndexPatternField( + { + name, + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + name + ); +}; + +describe('visBuilder sidebar field selector', function () { + const defaultProps = { + filterManager: {} as FilterManager, + getDetailsByField: mockGetDetailsByField, + header: 'mockHeader', + id: 'mockID', + }; + describe('FieldGroup', () => { + it('renders an empty accordion if no fields specified', async () => { + const { container } = render(); + + expect(container).toHaveTextContent(defaultProps.header); + expect(container).toHaveTextContent('0'); + expect(screen.queryAllByTestId('field-popover').length).toBeFalsy(); + + await fireEvent.click(screen.getByText(defaultProps.header)); + + expect(mockGetDetailsByField).not.toHaveBeenCalled(); + }); + + it('renders an accordion with Fields if fields provided', async () => { + const props = { + ...defaultProps, + fields: ['bytes', 'machine.ram', 'memory', 'phpmemory'].map(getFields), + }; + const { container } = render(); + + expect(container).toHaveTextContent(props.header); + expect(container).toHaveTextContent(props.fields.length.toString()); + expect(screen.queryAllByTestId('field-popover').length).toBe(props.fields.length); + + await fireEvent.click(screen.getByText('memory')); + + expect(mockGetDetailsByField).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field_selector.tsx b/src/plugins/vis_builder/public/application/components/data_tab/field_selector.tsx index 6d3831363c1b..5c82419d5531 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/field_selector.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/field_selector.tsx @@ -3,21 +3,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState, useEffect, useMemo } from 'react'; +import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { EuiFlexItem, EuiAccordion, EuiNotificationBadge, EuiTitle } from '@elastic/eui'; -import { FieldSearch } from './field_search'; -import { - IndexPatternField, - OPENSEARCH_FIELD_TYPES, - OSD_FIELD_TYPES, -} from '../../../../../data/public'; -import { FieldSelectorField } from './field_selector_field'; +import { IndexPattern, IndexPatternField, OSD_FIELD_TYPES } from '../../../../../data/public'; -import './field_selector.scss'; +import { COUNT_FIELD } from '../../utils/drag_drop'; import { useTypedSelector } from '../../utils/state_management'; -import { useIndexPatterns } from '../../utils/use'; -import { getAvailableFields } from './utils'; +import { useIndexPatterns, useSampleHits } from '../../utils/use'; +import { FieldSearch } from './field_search'; +import { Field, DraggableFieldButton } from './field'; +import { FieldDetails } from './types'; +import { getAvailableFields, getDetails } from './utils'; +import './field_selector.scss'; interface IFieldCategories { categorical: IndexPatternField[]; @@ -25,22 +23,18 @@ interface IFieldCategories { meta: IndexPatternField[]; } -const META_FIELDS: string[] = [ - OPENSEARCH_FIELD_TYPES._ID, - OPENSEARCH_FIELD_TYPES._INDEX, - OPENSEARCH_FIELD_TYPES._SOURCE, - OPENSEARCH_FIELD_TYPES._TYPE, -]; - export const FieldSelector = () => { const indexPattern = useIndexPatterns().selected; const fieldSearchValue = useTypedSelector((state) => state.visualization.searchField); + // TODO: instead of a single fetch of sampled hits for all fields, we should just use the agg service to get top hits or terms per field: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2780 + const hits = useSampleHits(); const [filteredFields, setFilteredFields] = useState([]); useEffect(() => { - const indexFields = indexPattern?.fields ?? []; + const indexFields = indexPattern?.fields.getAll() ?? []; const filteredSubset = getAvailableFields(indexFields).filter((field) => - field.displayName.includes(fieldSearchValue) + // case-insensitive field search + field.displayName.toLowerCase().includes(fieldSearchValue.toLowerCase()) ); setFilteredFields(filteredSubset); @@ -51,7 +45,7 @@ export const FieldSelector = () => { () => filteredFields?.reduce( (fieldGroups, currentField) => { - const category = getFieldCategory(currentField); + const category = getFieldCategory(currentField, indexPattern); fieldGroups[category].push(currentField); return fieldGroups; @@ -62,7 +56,14 @@ export const FieldSelector = () => { meta: [], } ), - [filteredFields] + [filteredFields, indexPattern] + ); + + const getDetailsByField = useCallback( + (ipField: IndexPatternField) => { + return getDetails(ipField, hits, indexPattern); + }, + [hits, indexPattern] ); return ( @@ -74,20 +75,30 @@ export const FieldSelector = () => {
{/* Count Field */} - + + - -
); @@ -95,37 +106,44 @@ export const FieldSelector = () => { interface FieldGroupProps { fields?: IndexPatternField[]; + getDetailsByField: (ipField: IndexPatternField) => FieldDetails; header: string; id: string; } -const FieldGroup = ({ fields, header, id }: FieldGroupProps) => ( - - {header} - - } - extraAction={ - - {fields?.length || 0} - - } - initialIsOpen - > - {fields?.map((field, i) => ( - - - - ))} - -); +export const FieldGroup = ({ fields, header, id, getDetailsByField }: FieldGroupProps) => { + return ( + + {header} + + } + extraAction={ + + {fields?.length || 0} + + } + initialIsOpen + > + {fields?.map((field, i) => ( + + + + ))} + + ); +}; -function getFieldCategory(field: IndexPatternField): keyof IFieldCategories { - if (META_FIELDS.includes(field.name)) return 'meta'; - if (field.type === OSD_FIELD_TYPES.NUMBER) return 'numerical'; +export const getFieldCategory = ( + { name, type }: IndexPatternField, + indexPattern: IndexPattern | undefined +): keyof IFieldCategories => { + const { metaFields = [] } = indexPattern ?? {}; + if (metaFields.includes(name)) return 'meta'; + if (type === OSD_FIELD_TYPES.NUMBER) return 'numerical'; return 'categorical'; -} +}; diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field_selector_field.tsx b/src/plugins/vis_builder/public/application/components/data_tab/field_selector_field.tsx deleted file mode 100644 index a87e2d184eed..000000000000 --- a/src/plugins/vis_builder/public/application/components/data_tab/field_selector_field.tsx +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import React, { useState } from 'react'; -import { IndexPatternField } from '../../../../../data/public'; -import { FieldButton, FieldIcon } from '../../../../../opensearch_dashboards_react/public'; -import { useDrag } from '../../utils/drag_drop/drag_drop_context'; -import { COUNT_FIELD } from '../../utils/drag_drop/types'; - -import './field_selector_field.scss'; - -export interface FieldSelectorFieldProps { - field: Partial & Pick; -} - -// TODO: -// 1. Add field sections (Available fields, popular fields from src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx) -// 2. Add popover for fields stats from discover as well -export const FieldSelectorField = ({ field }: FieldSelectorFieldProps) => { - const [infoIsOpen, setOpen] = useState(false); - const [dragProps] = useDrag({ - namespace: 'field-data', - value: field.name || COUNT_FIELD, - }); - - function togglePopover() { - setOpen(!infoIsOpen); - } - - function wrapOnDot(str?: string) { - // u200B is a non-width white-space character, which allows - // the browser to efficiently word-wrap right after the dot - // without us having to draw a lot of extra DOM elements, etc - return str ? str.replace(/\./g, '.\u200B') : ''; - } - - const fieldName = ( - - {wrapOnDot(field.displayName)} - - ); - - return ( - } - // fieldAction={actionButton} - fieldName={fieldName} - {...dragProps} - /> - ); -}; diff --git a/src/plugins/vis_builder/public/application/components/data_tab/types.ts b/src/plugins/vis_builder/public/application/components/data_tab/types.ts new file mode 100644 index 000000000000..c7e0327070e7 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/types.ts @@ -0,0 +1,22 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export interface FieldDetails { + buckets: Bucket[]; + error: string; + exists: number; + total: number; +} + +export interface FieldValueCounts extends Partial { + missing?: number; +} + +export interface Bucket { + count: number; + display: string; + percent: number; + value: string; +} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/utils/field_calculator.test.ts b/src/plugins/vis_builder/public/application/components/data_tab/utils/field_calculator.test.ts new file mode 100644 index 000000000000..4f1dfd98fc3b --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/utils/field_calculator.test.ts @@ -0,0 +1,268 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import _ from 'lodash'; +// @ts-ignore +import realHits from 'fixtures/real_hits.js'; +// @ts-ignore +import stubbedLogstashFields from 'fixtures/logstash_fields'; +import { coreMock } from '../../../../../../../core/public/mocks'; +import { IndexPattern, IndexPatternField } from '../../../../../../data/public'; +import { getStubIndexPattern } from '../../../../../../data/public/test_utils'; +import { Bucket } from '../types'; +import { + groupValues, + getFieldValues, + getFieldValueCounts, + FieldValueCountsParams, +} from './field_calculator'; + +let indexPattern: IndexPattern; + +describe('field_calculator', function () { + beforeEach(function () { + indexPattern = getStubIndexPattern( + 'logstash-*', + (cfg: any) => cfg, + 'time', + stubbedLogstashFields(), + coreMock.createSetup() + ); + }); + + describe('groupValues', function () { + let groups: Record; + let grouped: boolean; + let values: any[]; + beforeEach(function () { + values = [ + ['foo', 'bar'], + 'foo', + 'foo', + undefined, + ['foo', 'bar'], + 'bar', + 'baz', + null, + null, + null, + 'foo', + undefined, + ]; + groups = groupValues(values, grouped); + }); + + it('should return an object', function () { + expect(groups).toBeInstanceOf(Object); + }); + + it('should throw an error if any value is a plain object', function () { + expect(function () { + groupValues([{}, true, false], grouped); + }).toThrowError(); + }); + + it('should handle values with dots in them', function () { + values = ['0', '0.........', '0.......,.....']; + groups = groupValues(values, grouped); + expect(groups[values[0]].count).toBe(1); + expect(groups[values[1]].count).toBe(1); + expect(groups[values[2]].count).toBe(1); + }); + + it('should have a key for value in the array when not grouping array terms', function () { + expect(_.keys(groups).length).toBe(3); + expect(groups.foo).toBeInstanceOf(Object); + expect(groups.bar).toBeInstanceOf(Object); + expect(groups.baz).toBeInstanceOf(Object); + }); + + it('should count array terms independently', function () { + expect(groups['foo,bar']).toBeUndefined(); + expect(groups.foo.count).toBe(5); + expect(groups.bar.count).toBe(3); + expect(groups.baz.count).toBe(1); + }); + + describe('grouped array terms', function () { + beforeEach(function () { + grouped = true; + groups = groupValues(values, grouped); + }); + + it('should group array terms when grouped is true', function () { + expect(_.keys(groups).length).toBe(4); + expect(groups['foo,bar']).toBeInstanceOf(Object); + }); + + it('should contain the original array as the value', function () { + expect(groups['foo,bar'].value).toEqual(['foo', 'bar']); + }); + + it('should count the pairs separately from the values they contain', function () { + expect(groups['foo,bar'].count).toBe(2); + expect(groups.foo.count).toBe(3); + expect(groups.bar.count).toBe(1); + }); + }); + }); + + describe('getFieldValues', function () { + let hits: any; + + beforeEach(function () { + hits = _.each(_.cloneDeep(realHits), (hit) => indexPattern.flattenHit(hit)); + }); + + it('should return an array of values for _source fields', function () { + const extensions = getFieldValues({ + hits, + field: indexPattern.fields.getByName('extension') as IndexPatternField, + indexPattern, + }); + expect(extensions).toBeInstanceOf(Array); + expect( + _.filter(extensions, function (v) { + return v === 'html'; + }).length + ).toBe(8); + expect(_.uniq(_.clone(extensions)).sort()).toEqual(['gif', 'html', 'php', 'png']); + }); + + it('should return an array of values for core meta fields', function () { + const types = getFieldValues({ + hits, + field: indexPattern.fields.getByName('_type') as IndexPatternField, + indexPattern, + }); + expect(types).toBeInstanceOf(Array); + expect( + _.filter(types, function (v) { + return v === 'apache'; + }).length + ).toBe(18); + expect(_.uniq(_.clone(types)).sort()).toEqual(['apache', 'nginx']); + }); + }); + + describe('getFieldValueCounts', function () { + let params: FieldValueCountsParams; + beforeEach(function () { + params = { + hits: _.cloneDeep(realHits), + field: indexPattern.fields.getByName('extension') as IndexPatternField, + count: 3, + indexPattern, + }; + }); + + it('counts the top 5 values by default', function () { + params.hits = params.hits.map((hit: Record, i) => ({ + ...hit, + _source: { + extension: `${hit._source.extension}-${i}`, + }, + })); + params.count = undefined; + const extensions = getFieldValueCounts(params); + expect(extensions).toBeInstanceOf(Object); + expect(extensions.buckets).toBeInstanceOf(Array); + const buckets = extensions.buckets as Bucket[]; + expect(buckets.length).toBe(5); + expect(extensions.error).toBeUndefined(); + }); + + it('counts only distinct values if less than default', function () { + params.count = undefined; + const extensions = getFieldValueCounts(params); + expect(extensions).toBeInstanceOf(Object); + expect(extensions.buckets).toBeInstanceOf(Array); + const buckets = extensions.buckets as Bucket[]; + expect(buckets.length).toBe(4); + expect(extensions.error).toBeUndefined(); + }); + + it('counts only distinct values if less than specified count', function () { + params.count = 10; + const extensions = getFieldValueCounts(params); + expect(extensions).toBeInstanceOf(Object); + expect(extensions.buckets).toBeInstanceOf(Array); + const buckets = extensions.buckets as Bucket[]; + expect(buckets.length).toBe(4); + expect(extensions.error).toBeUndefined(); + }); + + it('counts the top 3 values', function () { + const extensions = getFieldValueCounts(params); + expect(extensions).toBeInstanceOf(Object); + expect(extensions.buckets).toBeInstanceOf(Array); + const buckets = extensions.buckets as Bucket[]; + expect(buckets.length).toBe(3); + expect(_.map(buckets, 'value')).toEqual(['html', 'gif', 'php']); + expect(extensions.error).toBeUndefined(); + }); + + it('fails to analyze geo and attachment types', function () { + params.field = indexPattern.fields.getByName('point') as IndexPatternField; + expect(getFieldValueCounts(params).error).not.toBeUndefined(); + + params.field = indexPattern.fields.getByName('area') as IndexPatternField; + expect(getFieldValueCounts(params).error).not.toBeUndefined(); + + params.field = indexPattern.fields.getByName('request_body') as IndexPatternField; + expect(getFieldValueCounts(params).error).not.toBeUndefined(); + }); + + it('fails to analyze fields that are in the mapping, but not the hits', function () { + params.field = indexPattern.fields.getByName('ip') as IndexPatternField; + expect(getFieldValueCounts(params).error).not.toBeUndefined(); + }); + + it('counts the total hits', function () { + expect(getFieldValueCounts(params).total).toBe(params.hits.length); + }); + + it('counts the hits the field exists in', function () { + params.field = indexPattern.fields.getByName('phpmemory') as IndexPatternField; + expect(getFieldValueCounts(params).exists).toBe(5); + }); + + it('catches and returns errors', function () { + params.hits = params.hits.map((hit: Record) => ({ + ...hit, + _source: { + extension: { foo: hit._source.extension }, + }, + })); + params.grouped = true; + expect(typeof getFieldValueCounts(params).error).toBe('string'); + }); + }); +}); diff --git a/src/plugins/vis_builder/public/application/components/data_tab/utils/field_calculator.ts b/src/plugins/vis_builder/public/application/components/data_tab/utils/field_calculator.ts new file mode 100644 index 000000000000..bd3cde945d95 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/utils/field_calculator.ts @@ -0,0 +1,124 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { IndexPattern, IndexPatternField } from '../../../../../../data/public'; +import { FieldValueCounts } from '../types'; + +const NO_ANALYSIS_TYPES = ['geo_point', 'geo_shape', 'attachment']; + +interface FieldValuesParams { + hits: Array>; + field: IndexPatternField; + indexPattern: IndexPattern; +} + +interface FieldValueCountsParams extends FieldValuesParams { + count?: number; + grouped?: boolean; +} + +const getFieldValues = ({ hits, field, indexPattern }: FieldValuesParams) => { + // For multi-value fields, we want to flatten based on the parent name instead + const name = field.subType?.multi?.parent ?? field.name; + const flattenHit = indexPattern.flattenHit; + return hits.map((hit) => flattenHit(hit)[name]); +}; + +const getFieldValueCounts = (params: FieldValueCountsParams): FieldValueCounts => { + const { hits, field, indexPattern, count = 5, grouped = false } = params; + const { type: fieldType } = field; + + if (NO_ANALYSIS_TYPES.includes(fieldType)) { + return { + error: i18n.translate( + 'visBuilder.fieldChooser.fieldCalculator.analysisIsNotAvailableForGeoFieldsErrorMessage', + { + defaultMessage: 'Analysis is not available for {fieldType} fields.', + values: { + fieldType, + }, + } + ), + }; + } + + const allValues = getFieldValues({ hits, field, indexPattern }); + const missing = allValues.filter((v) => v === undefined || v === null).length; + + try { + const groups = groupValues(allValues, grouped); + const counts = Object.keys(groups) + .sort((a, b) => groups[b].count - groups[a].count) + .slice(0, count) + .map((key) => ({ + value: groups[key].value, + count: groups[key].count, + percent: (groups[key].count / (hits.length - missing)) * 100, + display: indexPattern.getFormatterForField(field).convert(groups[key].value), + })); + + if (hits.length === missing) { + return { + error: i18n.translate( + 'visBuilder.fieldChooser.fieldCalculator.fieldIsNotPresentInDocumentsErrorMessage', + { + defaultMessage: + 'This field is present in your OpenSearch mapping but not in the {hitsLength} documents sampled. You may still be able to visualize it.', + values: { + hitsLength: hits.length, + }, + } + ), + }; + } + + return { + total: hits.length, + exists: hits.length - missing, + missing, + buckets: counts, + }; + } catch (e) { + return { + error: e instanceof Error ? e.message : String(e), + }; + } +}; + +const groupValues = ( + allValues: any[], + grouped?: boolean +): Record => { + const values = grouped ? allValues : allValues.flat(); + + return values + .filter((v) => { + if (v instanceof Object && !Array.isArray(v)) { + throw new Error( + i18n.translate( + 'visBuilder.fieldChooser.fieldCalculator.analysisIsNotAvailableForObjectFieldsErrorMessage', + { + defaultMessage: 'Analysis is not available for object fields.', + } + ) + ); + } + return v !== undefined && v !== null; + }) + .reduce((groups, value) => { + if (groups.hasOwnProperty(value)) { + groups[value].count++; + } else { + groups[value] = { + value, + count: 1, + }; + } + return groups; + }, {}); +}; + +export { FieldValueCountsParams, groupValues, getFieldValues, getFieldValueCounts }; diff --git a/src/plugins/vis_builder/public/application/components/data_tab/utils/get_field_details.ts b/src/plugins/vis_builder/public/application/components/data_tab/utils/get_field_details.ts new file mode 100644 index 000000000000..75b8b60c0c67 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/utils/get_field_details.ts @@ -0,0 +1,57 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; + +import { IndexPattern, IndexPatternField } from '../../../../../../data/public'; +import { FieldDetails } from '../types'; + +import { getFieldValueCounts } from './field_calculator'; + +export function getFieldDetails( + field: IndexPatternField, + hits: Array>, + indexPattern?: IndexPattern +): FieldDetails { + const defaultDetails = { + error: '', + exists: 0, + total: 0, + buckets: [], + }; + if (!indexPattern) { + return { + ...defaultDetails, + error: i18n.translate('visBuilder.fieldSelector.noIndexPatternSelectedErrorMessage', { + defaultMessage: 'Index pattern not specified.', + }), + }; + } + if (!hits.length) { + return { + ...defaultDetails, + error: i18n.translate('visBuilder.fieldSelector.noHits', { + defaultMessage: + 'No documents match the selected query and filters. Try increasing time range or removing filters.', + }), + }; + } + const details = { + ...defaultDetails, + ...getFieldValueCounts({ + hits, + field, + indexPattern, + count: 5, + grouped: false, + }), + }; + if (details.buckets) { + for (const bucket of details.buckets) { + bucket.display = indexPattern.getFormatterForField(field).convert(bucket.value); + } + } + return details; +} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/utils/index.ts b/src/plugins/vis_builder/public/application/components/data_tab/utils/index.ts index dd0cdea3e23e..2900a66d8f1e 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/utils/index.ts +++ b/src/plugins/vis_builder/public/application/components/data_tab/utils/index.ts @@ -4,3 +4,4 @@ */ export { getAvailableFields } from './get_available_fields'; +export { getFieldDetails as getDetails } from './get_field_details'; diff --git a/src/plugins/vis_builder/public/application/utils/drag_drop/drag_drop_context.tsx b/src/plugins/vis_builder/public/application/utils/drag_drop/drag_drop_context.tsx index c0f8725a501a..b5c809c9b359 100644 --- a/src/plugins/vis_builder/public/application/utils/drag_drop/drag_drop_context.tsx +++ b/src/plugins/vis_builder/public/application/utils/drag_drop/drag_drop_context.tsx @@ -14,7 +14,7 @@ import React, { } from 'react'; import { DragDataType } from './types'; -// TODO: Replace any with corret type +// TODO: Replace any with correct type // TODO: Split into separate files interface IDragDropContext { data: DragDataType; diff --git a/src/plugins/vis_builder/public/application/utils/drag_drop/index.ts b/src/plugins/vis_builder/public/application/utils/drag_drop/index.ts index 3799a2eb6052..4516a90575ab 100644 --- a/src/plugins/vis_builder/public/application/utils/drag_drop/index.ts +++ b/src/plugins/vis_builder/public/application/utils/drag_drop/index.ts @@ -4,3 +4,4 @@ */ export * from './drag_drop_context'; +export * from './types'; diff --git a/src/plugins/vis_builder/public/application/utils/use/index.ts b/src/plugins/vis_builder/public/application/utils/use/index.ts index 3ba3ca359072..1cc0b28dc89a 100644 --- a/src/plugins/vis_builder/public/application/utils/use/index.ts +++ b/src/plugins/vis_builder/public/application/utils/use/index.ts @@ -4,6 +4,8 @@ */ export { useAggs } from './use_aggs'; -export { useVisualizationType } from './use_visualization_type'; export { useIndexPatterns } from './use_index_pattern'; +export { useOnAddFilter } from './use_on_add_filter'; +export { useSampleHits } from './use_sample_hits'; export { useSavedVisBuilderVis } from './use_saved_vis_builder_vis'; +export { useVisualizationType } from './use_visualization_type'; diff --git a/src/plugins/vis_builder/public/application/utils/use/use_on_add_filter.ts b/src/plugins/vis_builder/public/application/utils/use/use_on_add_filter.ts new file mode 100644 index 000000000000..791521fccad5 --- /dev/null +++ b/src/plugins/vis_builder/public/application/utils/use/use_on_add_filter.ts @@ -0,0 +1,35 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { useCallback } from 'react'; +import { IndexPatternField, opensearchFilters } from '../../../../../data/public'; +import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; +import { VisBuilderServices } from '../../../types'; +import { useIndexPatterns } from './use_index_pattern'; + +export const useOnAddFilter = () => { + const { + services: { + data: { + query: { filterManager }, + }, + }, + } = useOpenSearchDashboards(); + const indexPattern = useIndexPatterns().selected; + const { id = '' } = indexPattern ?? {}; + return useCallback( + (fieldToFilter: IndexPatternField | string, value: string, operation: '+' | '-') => { + const newFilters = opensearchFilters.generateFilters( + filterManager, + fieldToFilter, + value, + operation, + id + ); + return filterManager.addFilters(newFilters); + }, + [filterManager, id] + ); +}; diff --git a/src/plugins/vis_builder/public/application/utils/use/use_sample_hits.ts b/src/plugins/vis_builder/public/application/utils/use/use_sample_hits.ts new file mode 100644 index 000000000000..f3ed75a4dd6a --- /dev/null +++ b/src/plugins/vis_builder/public/application/utils/use/use_sample_hits.ts @@ -0,0 +1,80 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { useEffect, useLayoutEffect, useState } from 'react'; +import { SortDirection } from '../../../../../data/public'; +import { IExpressionLoaderParams } from '../../../../../expressions/public'; +import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; +import { VisBuilderServices } from '../../../types'; +import { useIndexPatterns } from './use_index_pattern'; + +export const useSampleHits = () => { + const { + services: { + data: { + query: { + filterManager, + queryString, + state$, + timefilter: { timefilter }, + }, + search: { searchSource }, + }, + uiSettings: config, + }, + } = useOpenSearchDashboards(); + const indexPattern = useIndexPatterns().selected; + const [hits, setHits] = useState>>([]); + const [searchContext, setSearchContext] = useState({ + query: queryString.getQuery(), + filters: filterManager.getFilters(), + }); + + useEffect(() => { + async function getData() { + if (indexPattern && searchContext) { + const newSearchSource = await searchSource.create(); + const timeRangeFilter = timefilter.createFilter(indexPattern); + + newSearchSource + .setField('index', indexPattern) + .setField('size', config.get('discover:sampleSize') ?? 500) + .setField('sort', [{ [indexPattern.timeFieldName || '_score']: 'desc' as SortDirection }]) + .setField('filter', [ + ...(searchContext.filters ?? []), + ...(timeRangeFilter ? [timeRangeFilter] : []), + ]); + + if (searchContext.query) { + const contextQuery = + searchContext.query instanceof Array ? searchContext.query[0] : searchContext.query; + + newSearchSource.setField('query', contextQuery); + } + + const searchResponse = await newSearchSource.fetch(); + + setHits(searchResponse.hits.hits); + } + } + + getData(); + }, [config, searchContext, searchSource, indexPattern, timefilter]); + + useLayoutEffect(() => { + const subscription = state$.subscribe(({ state }) => { + setSearchContext({ + query: state.query, + filters: state.filters, + }); + }); + + return () => { + subscription.unsubscribe(); + }; + }, [state$]); + + return hits; +}; From 5608f822f6b653aa508c4b4d5845a0e24d2b9de3 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 4 Nov 2022 16:08:29 -0700 Subject: [PATCH 14/25] Bump makelogs to remove dependency on got (#2801) * Also dusted off the lock file a bit Fixes #1764 Signed-off-by: Miki Signed-off-by: Miki --- CHANGELOG.md | 9 ++- yarn.lock | 221 +++------------------------------------------------ 2 files changed, 18 insertions(+), 212 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be347e38a846..753971bd5823 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### 🛡 Security -* [Legacy Maps Plugin] Prevent reverse-tabnabbing ([#2540](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2540)) +- [Legacy Maps Plugin] Prevent reverse-tabnabbing ([#2540](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2540)) +- Eliminate dependency on `got` versions older than 11.8.5 ([#2801](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2801)) ### 📈 Features/Enhancements @@ -49,7 +50,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Vis Builder] Fixes visualization shift when editing agg ([2401](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2401)) - [Vis Builder] Renames "Histogram" to "Bar" in vis type picker ([2401](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2401)) - [Vis Builder] Update vislib params and misc fixes ([2610](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2610)) -* [Vis Builder] Bug fixes for datasource picker and auto time interval ([2632](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2632)) +- [Vis Builder] Bug fixes for datasource picker and auto time interval ([2632](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2632)) - [MD] Add data source param to low-level search call in Discover ([#2431](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2431)) - [Multi DataSource] Skip data source view in index pattern step when pick default ([#2574](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2574)) - [Multi DataSource] Address UX comments on Edit Data source page ([#2629](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2629)) @@ -69,8 +70,8 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### 📝 Documentation -* [MD] Add design documents of multiple data source feature [#2538](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2538) -* [MD] Tweak multiple data source design doc [#2724](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2724) +- [MD] Add design documents of multiple data source feature [#2538](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2538) +- [MD] Tweak multiple data source design doc [#2724](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2724) ### 🛠 Maintenance diff --git a/yarn.lock b/yarn.lock index 2ed05fd39fa0..d98a153726af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1331,9 +1331,9 @@ "@hapi/validate" "1.x.x" "@elastic/makelogs@^6.1.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@elastic/makelogs/-/makelogs-6.1.0.tgz#1ea61a01b4680c0e904c5b8be3d325f427030e16" - integrity sha512-iFhSpgOcmv7q65AiTzny2fkhddVdG/6yoX7pUsvwJo9Cc0B6ySVOlwweAWntkwQC3Y1IQpm9gpQUe2GwsyRUkQ== + version "6.1.1" + resolved "https://registry.yarnpkg.com/@elastic/makelogs/-/makelogs-6.1.1.tgz#5bc173b16acdfd7844fd85c97824ddcffd67cfb3" + integrity sha512-cmfXFQITwyT4SV+Ryerg/vVbGQ9E2BhYKQ9flG85Ba3blGVmOjkgv7TYQam6xAIvGXFGBBrcyqEwmuw7xZ5ZNQ== dependencies: async "^1.4.2" commander "^5.0.0" @@ -1342,7 +1342,6 @@ moment "^2.10.6" progress "^1.1.8" through2 "^2.0.0" - update-notifier "^0.5.0" "@elastic/node-crypto@1.1.1": version "1.1.1" @@ -6161,20 +6160,6 @@ concat-stream@^1.4.7, concat-stream@^1.5.0: readable-stream "^2.2.2" typedarray "^0.0.6" -configstore@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021" - integrity sha1-w1eB0FAdJowlxUuLF/YkDopPsCE= - dependencies: - graceful-fs "^4.1.2" - mkdirp "^0.5.0" - object-assign "^4.0.1" - os-tmpdir "^1.0.0" - osenv "^0.1.0" - uuid "^2.0.1" - write-file-atomic "^1.1.2" - xdg-basedir "^2.0.0" - console-browserify@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" @@ -6970,11 +6955,6 @@ deep-equal@^2.0.5: which-collection "^1.0.1" which-typed-array "^1.1.2" -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - deep-freeze-strict@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/deep-freeze-strict/-/deep-freeze-strict-1.1.1.tgz#77d0583ca24a69be4bbd9ac2fae415d55523e5b0" @@ -7402,7 +7382,7 @@ duplexer@^0.1.1: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== -duplexify@^3.2.0, duplexify@^3.4.2, duplexify@^3.6.0: +duplexify@^3.4.2, duplexify@^3.6.0: version "3.7.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== @@ -9414,7 +9394,7 @@ globjoin@^0.1.4: resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM= -got@11.8.5: +got@11.8.5, got@^11.8.2: version "11.8.5" resolved "https://registry.yarnpkg.com/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046" integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ== @@ -9431,45 +9411,7 @@ got@11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" -got@^11.8.2: - version "11.8.3" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.3.tgz#f496c8fdda5d729a90b4905d2b07dbd148170770" - integrity sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg== - dependencies: - "@sindresorhus/is" "^4.0.0" - "@szmarczak/http-timer" "^4.0.5" - "@types/cacheable-request" "^6.0.1" - "@types/responselike" "^1.0.0" - cacheable-lookup "^5.0.3" - cacheable-request "^7.0.2" - decompress-response "^6.0.0" - http2-wrapper "^1.0.0-beta.5.2" - lowercase-keys "^2.0.0" - p-cancelable "^2.0.0" - responselike "^2.0.0" - -got@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca" - integrity sha1-5dDtSvVfw+701WAHdp2YGSvLLso= - dependencies: - duplexify "^3.2.0" - infinity-agent "^2.0.0" - is-redirect "^1.0.0" - is-stream "^1.0.0" - lowercase-keys "^1.0.0" - nested-error-stacks "^1.0.0" - object-assign "^3.0.0" - prepend-http "^1.0.0" - read-all-stream "^3.0.0" - timed-out "^2.0.0" - -graceful-fs@4.X, graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: - version "4.2.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" - integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== - -graceful-fs@^4.2.0: +graceful-fs@4.X, graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== @@ -10261,11 +10203,6 @@ infer-owner@^1.0.3, infer-owner@^1.0.4: resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== -infinity-agent@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/infinity-agent/-/infinity-agent-2.0.3.tgz#45e0e2ff7a9eb030b27d62b74b3744b7a7ac4216" - integrity sha1-ReDi/3qesDCyfWK3SzdEt6esQhY= - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -10289,7 +10226,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: +ini@^1.3.4, ini@^1.3.5: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== @@ -10696,11 +10633,6 @@ is-nil@^1.0.0: resolved "https://registry.yarnpkg.com/is-nil/-/is-nil-1.0.1.tgz#2daba29e0b585063875e7b539d071f5b15937969" integrity sha1-LauingtYUGOHXntTnQcfWxWTeWk= -is-npm@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" - integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ= - is-number-object@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" @@ -10788,11 +10720,6 @@ is-promise@^2.1.0, is-promise@^2.2.2: resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== -is-redirect@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" - integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= - is-regex@^1.0.5, is-regex@^1.1.0, is-regex@^1.1.1, is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -10830,7 +10757,7 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" -is-stream@^1.0.0, is-stream@^1.1.0: +is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -11869,13 +11796,6 @@ language-tags@^1.0.5: dependencies: language-subtag-registry "~0.3.2" -latest-version@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-1.0.1.tgz#72cfc46e3e8d1be651e1ebb54ea9f6ea96f374bb" - integrity sha1-cs/Ebj6NG+ZR4eu1Tqn26pbzdLs= - dependencies: - package-json "^1.0.0" - lazystream@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" @@ -12390,11 +12310,6 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3 dependencies: js-tokens "^3.0.0 || ^4.0.0" -lowercase-keys@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - lowercase-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" @@ -12885,7 +12800,7 @@ mkdirp@^0.3.5: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" integrity sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc= -mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.0: +mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.0: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -13139,13 +13054,6 @@ neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1, neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -nested-error-stacks@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz#19f619591519f096769a5ba9a86e6eeec823c3cf" - integrity sha1-GfYZWRUZ8JZ2mlupqG5u7sgjw88= - dependencies: - inherits "~2.0.1" - nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5" @@ -13491,11 +13399,6 @@ object-assign@4.X, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4. resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -object-assign@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" - integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= - object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" @@ -13760,7 +13663,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.0, osenv@^0.1.4: +osenv@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -13887,14 +13790,6 @@ package-hash@^4.0.0: lodash.flattendeep "^4.4.0" release-zalgo "^1.0.0" -package-json@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/package-json/-/package-json-1.2.0.tgz#c8ecac094227cdf76a316874ed05e27cc939a0e0" - integrity sha1-yOysCUInzfdqMWh07QXifMk5oOA= - dependencies: - got "^3.2.0" - registry-url "^3.0.0" - pako@^1.0.5, pako@~1.0.2, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -14369,11 +14264,6 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prepend-http@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= - prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" @@ -14679,16 +14569,6 @@ raw-loader@^4.0.2: loader-utils "^2.0.0" schema-utils "^3.0.0" -rc@^1.0.1: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - re-reselect@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/re-reselect/-/re-reselect-3.4.0.tgz#0f2303f3c84394f57f0cd31fea08a1ca4840a7cd" @@ -15031,14 +14911,6 @@ reactcss@1.2.3: dependencies: lodash "^4.0.1" -read-all-stream@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" - integrity sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po= - dependencies: - pinkie-promise "^2.0.0" - readable-stream "^2.0.0" - read-installed@~4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" @@ -15300,13 +15172,6 @@ regexpu-core@^5.0.1: unicode-match-property-ecmascript "^2.0.0" unicode-match-property-value-ecmascript "^2.0.0" -registry-url@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" - integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI= - dependencies: - rc "^1.0.1" - regjsgen@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" @@ -15451,13 +15316,6 @@ repeat-string@^1.5.4, repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -repeating@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" - integrity sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw= - dependencies: - is-finite "^1.0.0" - replace-ext@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" @@ -15897,14 +15755,7 @@ selenium-webdriver@^4.0.0-alpha.7: rimraf "^2.7.1" tmp "0.0.30" -semver-diff@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" - integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY= - dependencies: - semver "^5.0.3" - -"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.3.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -16124,7 +15975,7 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -slide@^1.1.5, slide@~1.1.3: +slide@~1.1.3: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= @@ -16541,13 +16392,6 @@ string-argv@~0.3.1: resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== -string-length@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac" - integrity sha1-VpcPscOFWOnnC3KL894mmsRa36w= - dependencies: - strip-ansi "^3.0.0" - string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -16763,7 +16607,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@2.0.1, strip-json-comments@~2.0.1: +strip-json-comments@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= @@ -17245,11 +17089,6 @@ through2@^3.0.1: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= -timed-out@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a" - integrity sha1-84sK6B03R9YoAB9B2vxlKs5nHAo= - timers-browserify@^2.0.4: version "2.0.12" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" @@ -17950,19 +17789,6 @@ upath@^1.1.1: resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== -update-notifier@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-0.5.0.tgz#07b5dc2066b3627ab3b4f530130f7eddda07a4cc" - integrity sha1-B7XcIGazYnqztPUwEw9+3doHpMw= - dependencies: - chalk "^1.0.0" - configstore "^1.0.0" - is-npm "^1.0.0" - latest-version "^1.0.0" - repeating "^1.1.2" - semver-diff "^2.0.0" - string-length "^1.0.0" - uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -18094,11 +17920,6 @@ uuid@8.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.0.0.tgz#bc6ccf91b5ff0ac07bbcdbf1c7c4e150db4dbb6c" integrity sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw== -uuid@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" - integrity sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho= - uuid@^3.3.2, uuid@^3.3.3: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" @@ -18995,15 +18816,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write-file-atomic@^1.1.2: - version "1.3.4" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" - integrity sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8= - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - write-file-atomic@^2.4.2: version "2.4.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" @@ -19074,13 +18886,6 @@ x-is-string@^0.1.0: resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= -xdg-basedir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" - integrity sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I= - dependencies: - os-homedir "^1.0.0" - xhr@^2.0.1: version "2.6.0" resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" From f90f3238b91feb4b4649ffbd83dd8457af89647a Mon Sep 17 00:00:00 2001 From: Ashwin P Chandran Date: Fri, 4 Nov 2022 17:13:34 -0700 Subject: [PATCH 15/25] Change VisBuilder flag for docker config (#2804) Signed-off-by: Ashwin P Chandran Signed-off-by: Ashwin P Chandran --- .../docker_generator/resources/bin/opensearch-dashboards-docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/opensearch-dashboards-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/opensearch-dashboards-docker index dc05bf8e0910..a5cefbc2397c 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/opensearch-dashboards-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/opensearch-dashboards-docker @@ -149,7 +149,7 @@ opensearch_dashboards_vars=( telemetry.optIn telemetry.optInStatusUrl telemetry.sendUsageFrom - wizard.enabled + vis_builder.enabled data_source.enabled data_source.encryption.wrappingKeyName data_source.encryption.wrappingKeyNamespace From fe4b8607b248fa379ce49ac46f2879b93771955c Mon Sep 17 00:00:00 2001 From: Kristen Tian <105667444+kristenTian@users.noreply.github.com> Date: Mon, 7 Nov 2022 15:27:09 -0800 Subject: [PATCH 16/25] [MD] Add explicit no spellcheck on password fields (#2818) Signed-off-by: Kristen Tian Signed-off-by: Kristen Tian --- CHANGELOG.md | 1 + .../__snapshots__/create_data_source_wizard.test.tsx.snap | 4 ++++ .../__snapshots__/create_data_source_form.test.tsx.snap | 6 ++++++ .../components/create_form/create_data_source_form.tsx | 1 + .../__snapshots__/edit_data_source.test.tsx.snap | 2 ++ .../__snapshots__/edit_data_source_form.test.tsx.snap | 2 ++ .../components/edit_form/edit_data_source_form.tsx | 1 + .../__snapshots__/update_password_modal.test.tsx.snap | 6 ++++++ .../update_password_modal/update_password_modal.tsx | 2 ++ 9 files changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 753971bd5823..d77b23d860b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Legacy Maps Plugin] Prevent reverse-tabnabbing ([#2540](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2540)) - Eliminate dependency on `got` versions older than 11.8.5 ([#2801](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2801)) +- [Multi DataSource] Add explicit no spellcheck on password fields ([#2818](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2818)) ### 📈 Features/Enhancements diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/__snapshots__/create_data_source_wizard.test.tsx.snap b/src/plugins/data_source_management/public/components/create_data_source_wizard/__snapshots__/create_data_source_wizard.test.tsx.snap index b4331e26f79d..c7e3152fca99 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/__snapshots__/create_data_source_wizard.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/__snapshots__/create_data_source_wizard.test.tsx.snap @@ -775,6 +775,7 @@ exports[`Datasource Management: Create Datasource Wizard case1: should load reso onChange={[Function]} onFocus={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="dual" value="" > @@ -811,6 +812,7 @@ exports[`Datasource Management: Create Datasource Wizard case1: should load reso onChange={[Function]} onFocus={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="password" value="" /> @@ -1749,6 +1751,7 @@ exports[`Datasource Management: Create Datasource Wizard case2: should fail to l onChange={[Function]} onFocus={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="dual" value="" > @@ -1785,6 +1788,7 @@ exports[`Datasource Management: Create Datasource Wizard case2: should fail to l onChange={[Function]} onFocus={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="password" value="" /> diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/__snapshots__/create_data_source_form.test.tsx.snap b/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/__snapshots__/create_data_source_form.test.tsx.snap index fcd197cc0827..0e8dc0a57a62 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/__snapshots__/create_data_source_form.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/__snapshots__/create_data_source_form.test.tsx.snap @@ -1537,6 +1537,7 @@ exports[`Datasource Management: Create Datasource form should create data source onChange={[Function]} onFocus={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="dual" value="test123" > @@ -1573,6 +1574,7 @@ exports[`Datasource Management: Create Datasource form should create data source onChange={[Function]} onFocus={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="password" value="test123" /> @@ -2469,6 +2471,7 @@ exports[`Datasource Management: Create Datasource form should render normally 1` onChange={[Function]} onFocus={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="dual" value="" > @@ -2505,6 +2508,7 @@ exports[`Datasource Management: Create Datasource form should render normally 1` onChange={[Function]} onFocus={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="password" value="" /> @@ -3418,6 +3422,7 @@ exports[`Datasource Management: Create Datasource form should throw validation e onChange={[Function]} onFocus={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="dual" value="test123" > @@ -3454,6 +3459,7 @@ exports[`Datasource Management: Create Datasource form should throw validation e onChange={[Function]} onFocus={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="password" value="test123" /> diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/create_data_source_form.tsx b/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/create_data_source_form.tsx index 429790231a5c..b159065822df 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/create_data_source_form.tsx +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/create_data_source_form.tsx @@ -276,6 +276,7 @@ export class CreateDataSourceForm extends React.Component< value={this.state.auth.credentials.password || ''} onChange={this.onChangePassword} onBlur={this.validatePassword} + spellCheck={false} data-test-subj="createDataSourceFormPasswordField" /> diff --git a/src/plugins/data_source_management/public/components/edit_data_source/__snapshots__/edit_data_source.test.tsx.snap b/src/plugins/data_source_management/public/components/edit_data_source/__snapshots__/edit_data_source.test.tsx.snap index a3d004457a78..2858167a08c0 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/__snapshots__/edit_data_source.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/edit_data_source/__snapshots__/edit_data_source.test.tsx.snap @@ -1018,6 +1018,7 @@ exports[`Datasource Management: Edit Datasource Wizard should load resources suc onBlur={[Function]} onChange={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="dual" value="********" > @@ -1054,6 +1055,7 @@ exports[`Datasource Management: Edit Datasource Wizard should load resources suc onBlur={[Function]} onChange={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="password" value="********" /> diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/__snapshots__/edit_data_source_form.test.tsx.snap b/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/__snapshots__/edit_data_source_form.test.tsx.snap index 1ce16bf131c2..84c105d68eef 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/__snapshots__/edit_data_source_form.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/__snapshots__/edit_data_source_form.test.tsx.snap @@ -965,6 +965,7 @@ exports[`Datasource Management: Edit Datasource Form Case 1: With Username & Pas onBlur={[Function]} onChange={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="dual" value="********" > @@ -1001,6 +1002,7 @@ exports[`Datasource Management: Edit Datasource Form Case 1: With Username & Pas onBlur={[Function]} onChange={[Function]} placeholder="Password to connect to data source" + spellCheck={false} type="password" value="********" /> diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.tsx b/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.tsx index bda8709cf509..46c91ad540c8 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.tsx @@ -585,6 +585,7 @@ export class EditDataSourceForm extends React.Component @@ -205,6 +206,7 @@ exports[`Datasource Management: Update Stored Password Modal should render norma id="generated-id" name="confirmUpdatedPassword" placeholder="Confirm Updated password" + spellcheck="false" type="password" value="" /> @@ -529,6 +531,7 @@ exports[`Datasource Management: Update Stored Password Modal should render norma onChange={[Function]} onFocus={[Function]} placeholder="Updated password" + spellCheck={false} type="dual" value="" > @@ -566,6 +569,7 @@ exports[`Datasource Management: Update Stored Password Modal should render norma onChange={[Function]} onFocus={[Function]} placeholder="Updated password" + spellCheck={false} type="password" value="" /> @@ -691,6 +695,7 @@ exports[`Datasource Management: Update Stored Password Modal should render norma onChange={[Function]} onFocus={[Function]} placeholder="Confirm Updated password" + spellCheck={false} type="dual" value="" > @@ -728,6 +733,7 @@ exports[`Datasource Management: Update Stored Password Modal should render norma onChange={[Function]} onFocus={[Function]} placeholder="Confirm Updated password" + spellCheck={false} type="password" value="" /> diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/update_password_modal.tsx b/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/update_password_modal.tsx index 95ca0abe6e90..693a8a84234e 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/update_password_modal.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/update_password_modal.tsx @@ -125,6 +125,7 @@ export const UpdatePasswordModal = ({ type={'dual'} value={newPassword} isInvalid={!isNewPasswordValid} + spellCheck={false} onChange={(e) => setNewPassword(e.target.value)} onBlur={validateNewPassword} /> @@ -149,6 +150,7 @@ export const UpdatePasswordModal = ({ type={'dual'} value={confirmNewPassword} isInvalid={!!isConfirmNewPasswordValid.length} + spellCheck={false} onChange={(e) => setConfirmNewPassword(e.target.value)} onBlur={validateConfirmNewPassword} /> From f12fa98da910bbaea50ca3b52f7b177c1531657b Mon Sep 17 00:00:00 2001 From: Anan Zhuang Date: Tue, 8 Nov 2022 16:54:07 -0800 Subject: [PATCH 17/25] [Bug][Table Visualization] Fix first column sort issue (#2828) Currently, the first column of table vis won't sort. This PR fixes the bug. Issue Resolved: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2827 Signed-off-by: Anan Zhuang Signed-off-by: Anan Zhuang --- CHANGELOG.md | 1 + .../public/components/table_vis_component.tsx | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d77b23d860b9..19cf2d4215a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Removes Add Integration button ([#2723](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2723)) - Change geckodriver version to make consistency ([#2772](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2772)) - [Multi DataSource] Update default audit log path ([#2793](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2793)) +- [Table Visualization] Fix first column sort issue ([#2828](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2828)) ### 🚞 Infrastructure diff --git a/src/plugins/vis_type_table_new/public/components/table_vis_component.tsx b/src/plugins/vis_type_table_new/public/components/table_vis_component.tsx index e24784d9eb1a..4a25395703b0 100644 --- a/src/plugins/vis_type_table_new/public/components/table_vis_component.tsx +++ b/src/plugins/vis_type_table_new/public/components/table_vis_component.tsx @@ -38,8 +38,10 @@ export const TableVisComponent = ({ const pagination = usePagination(visConfig, rows.length); const sortedRows = useMemo(() => { - return uiState.sort?.colIndex && uiState.sort.direction - ? orderBy(rows, columns[uiState.sort.colIndex]?.id, uiState.sort.direction) + return uiState.sort.colIndex !== null && + columns[uiState.sort.colIndex].id && + uiState.sort.direction + ? orderBy(rows, columns[uiState.sort.colIndex].id, uiState.sort.direction) : rows; }, [columns, rows, uiState]); @@ -58,8 +60,10 @@ export const TableVisComponent = ({ const dataGridColumns = getDataGridColumns(sortedRows, columns, table, event, uiState.width); const sortedColumns = useMemo(() => { - return uiState.sort?.colIndex && uiState.sort.direction - ? [{ id: dataGridColumns[uiState.sort.colIndex]?.id, direction: uiState.sort.direction }] + return uiState.sort.colIndex !== null && + dataGridColumns[uiState.sort.colIndex].id && + uiState.sort.direction + ? [{ id: dataGridColumns[uiState.sort.colIndex].id, direction: uiState.sort.direction }] : []; }, [dataGridColumns, uiState]); From 4fd67de27eb1d942450ee8272d2de2bb8ef2f96c Mon Sep 17 00:00:00 2001 From: Miki Date: Wed, 9 Nov 2022 10:19:20 -0800 Subject: [PATCH 18/25] Temporarily prevents `task-kill` exceptions on Windows when it is passed a `pid` for a process that is already dead (#2842) Ref: #2811 Signed-off-by: Miki Signed-off-by: Miki --- CHANGELOG.md | 1 + packages/osd-opensearch/src/cluster.js | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19cf2d4215a6..5358d5b89b66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Change geckodriver version to make consistency ([#2772](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2772)) - [Multi DataSource] Update default audit log path ([#2793](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2793)) - [Table Visualization] Fix first column sort issue ([#2828](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2828)) +- Temporary workaround for task-kill exceptions on Windows when it is passed a pid for a process that is already dead ([#2842](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2842)) ### 🚞 Infrastructure diff --git a/packages/osd-opensearch/src/cluster.js b/packages/osd-opensearch/src/cluster.js index 7b11b4edbbc5..b4912d677359 100644 --- a/packages/osd-opensearch/src/cluster.js +++ b/packages/osd-opensearch/src/cluster.js @@ -229,7 +229,22 @@ exports.Cluster = class Cluster { throw new Error('OpenSearch has not been started'); } - await treeKillAsync(this._process.pid); + /* Temporary fix for https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2811 + * + * `tree-kill` behaves differently on Windows, where it throws if `pid` is already dead, when + * compared to other operating systems, where it silently returns. + */ + try { + await treeKillAsync(this._process.pid); + } catch (ex) { + console.log('ex.message', ex.message); + if ( + process.platform === 'win32' && + !ex.message?.includes(`The process "${this._process.pid}" not found`) + ) { + throw ex; + } + } await this._outcome; } From d53fbf8684060cf0621f0f61c9fef636d4c4e97b Mon Sep 17 00:00:00 2001 From: Louis Chu Date: Thu, 10 Nov 2022 11:42:55 -0800 Subject: [PATCH 19/25] Add the release runbook to RELEASING.md (#2533) * Add release runbook on RELEASING.md Signed-off-by: Louis Chu * Update wording based on comments Signed-off-by: Louis Chu * Update wording based on comment Signed-off-by: Louis Chu * Resolve CHANGELOG.MD conflicts Signed-off-by: Louis Chu Signed-off-by: Louis Chu Signed-off-by: Louis Chu --- CHANGELOG.md | 1 + RELEASING.md | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5358d5b89b66..63eeb52edad8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### 📝 Documentation +- Add the release runbook to RELEASING.md ([#2533](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2533)) - [MD] Add design documents of multiple data source feature [#2538](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2538) - [MD] Tweak multiple data source design doc [#2724](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2724) diff --git a/RELEASING.md b/RELEASING.md index 50bb965b8d55..6be9bfc2b9ed 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,3 +1,76 @@ ## Releasing -This project follows [OpenSearch project branching, labelling, and releasing](https://github.com/opensearch-project/.github/blob/main/RELEASING.md). \ No newline at end of file +This project follows [OpenSearch project branching, labelling, and releasing](https://github.com/opensearch-project/.github/blob/main/RELEASING.md). + +## Runbook + +### Overview + +The OpenSearch project releases versioned distributions of OpenSearch, OpenSearch Dashboards, and the OpenSearch plugins. This runbook details the steps involved in performing major, minor, and patch version releases for the OpenSearch Dashboards project; these steps need to be completed by the release managers (RM) assigned to each release. The RM is also responsible for updating the release status on the release tracking issues maintained on GitHub ([example](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2230)). + +\*Important Dates: https://opensearch.org/releases.html + +### Release Phase 1 - Preparation + +For major and minor releases, the OpenSearch build repository [maintainers](https://github.com/opensearch-project/opensearch-build/blob/main/MAINTAINERS.md) will create a release issue in the OpenSearch Dashboards repository ([example](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2230)) which links to the overall issue in the OpenSearch build repository ([example](https://github.com/opensearch-project/opensearch-build/issues/2447)). For patch releases, they will only create the overall issue in the OpenSearch build repository ([example](https://github.com/opensearch-project/opensearch-build/issues/2650)). + +The OpenSearch Dashboards release issue will be assigned to the RM who should prepare for the release by reviewing all listed tasks. They should also compare the current release issue to the issue of the previous release version to ensure that all new processes have been captured. + +The RM should review the [public roadmap](https://github.com/orgs/opensearch-project/projects/1) and confirm the release scope with other OpenSearch Dashboards [maintainers](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/main/MAINTAINERS.md) as well as the feature owners. Since release labels are intended to highlight the features and fixes meant for the upcoming release, the RM should verify that all issues and pull requests are labelled accordingly. For example, if current release version was v2.3.0, all features not ready for the release should be labeled as v2.4.0 or later by discussing with the feature owners. The RM should also check all PRs for the current release version to confirm that they are merged into the `main` branch and their backported PRs are merged with all CI passing. + +#### How to validate that merged commits have been properly backported? + +1. For any PRs merged to main, make sure it has backport labels ([example - Add v2.3.0 release notes](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2318)) +2. Backport PR is generated automatically by [opensearch-trigger-bot](https://github.com/apps/opensearch-trigger-bot) + ([example - [Backport 2.3] Add v2.3.0 release notes](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2333)) +3. If the backport PR is not generated by opensearch-trigger-bot after 24 hours, create it manually following this [instruction](https://github.com/opensearch-project/.github/blob/main/RELEASING.md#backporting) +4. Ensure that all CI passed and it has two approvals. Then merge the PR. + +#### Prepare BWC data and update BWC versions + +Backward Compatibility Tests (BWC) are cypress tests that identify any obvious compatibility bugs with previous versions. The RM should generate test data and test locally following instructions [here](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/main/TESTING.md#backwards-compatibility-tests) and cut PR to include both generated data and version upgrade for automated build. (See example [PR](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2393/files)) + +#### Cut release branch for major / minor release + +For major / minor release, the RM should cut the release branch from the parent branch, [following OpenSearch project branching](https://github.com/opensearch-project/.github/blob/main/RELEASING.md#opensearch-branching) + +### Release Phase 2 - Pre-Release + +The release process for OpenSearch is centralized. Jenkins workflows are in place to regularly find differences in the OpenSearch and OpenSearch Dashboards components and create new snapshots for those that have been updated. The RM should update the release branch version in the distribution manifest (see example [PR](https://github.com/opensearch-project/opensearch-build/pull/2586/files)) and increment the parent branch version (see example [PR](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2295/files)). + +#### Write release notes + +OpenSearch Dashboards maintains a [CHANGELOG.md](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/main/CHANGELOG.md) and verifies it as part of the PR checklist step. For the time being, the RM should create release notes PR with the label `doc`, referring to the `CHANGELOG.md` (see example [PR](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2318)) + +### Release Phase 3 - Release testing + +#### Verify integration and BWC test results + +The automated integration test and BWC test are executed concurrently with the release artifacts build. The RM should examine the test results and assist in triaging the broken test case. + +Example build: + +x64: https://build.ci.opensearch.org/job/integ-test-opensearch-dashboards/995/ + +arm64: https://build.ci.opensearch.org/job/integ-test-opensearch-dashboards/996/ + +Example test results: +https://opensearch-project.github.io/opensearch-dashboards-functional-test/site/?version=2.3.0&build_number=4104&test_number=996 + +Note: change `arch` to match the operating system CPU architecture for which the build is being produced. + +#### Sanity test with tarball and docker image + +Once the release candidate artifacts are built, the RM should configure the OpenSearch cluster with OpenSearch Dashboards according to the [instructions in the OpenSearch build repo](https://github.com/opensearch-project/opensearch-build/issues/2447#issuecomment-1241406594) and produce sanity tests to identify broken functionalities caused by new features / code changes. If you find any, please file bug reports and assist in triaging the bugfix. + +### Release Phase 4 - Release Announcement + +Release artifacts and announcements will be available on https://opensearch.org/releases.html. Any website documentation changes will require a PR on the [OpenSearch documentation-website repo.](https://github.com/opensearch-project/documentation-website) + +### Release Phase 5 - Post-Release + +After a release is announced, OpenSearch build repository maintainers will trigger a job that creates a tag in each repository based on the commit hash and branch that was included in the release; the release tag could take a few hours to show up on GitHub. + +The RM should update the [release page](https://github.com/opensearch-project/OpenSearch-Dashboards/releases/) with the latest download URL and release notes after the release tag is created. + +If needed, the RM could conduct a retrospective review of the release, and publish their findings regarding any missed steps and process improvements. From 28c3df34d62c32f423e2006b41340e6e417da774 Mon Sep 17 00:00:00 2001 From: tygao Date: Sat, 12 Nov 2022 04:12:25 +0800 Subject: [PATCH 20/25] [VisBuilder] [BUG] fix empty workspace animation does not work in firefox (#2853) * fix: fix VisBuilder empty animation does not work in firefox Signed-off-by: raintygao * doc: add changelog for pull request Signed-off-by: raintygao Signed-off-by: raintygao --- CHANGELOG.md | 1 + .../vis_builder/public/application/components/workspace.scss | 1 + .../vis_builder/public/application/components/workspace.tsx | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63eeb52edad8..a2a7f5368714 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Multi DataSource] Update default audit log path ([#2793](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2793)) - [Table Visualization] Fix first column sort issue ([#2828](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2828)) - Temporary workaround for task-kill exceptions on Windows when it is passed a pid for a process that is already dead ([#2842](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2842)) +- [Vis Builder] Fix empty workspace animation does not work in firefox ([#2853](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2853)) ### 🚞 Infrastructure diff --git a/src/plugins/vis_builder/public/application/components/workspace.scss b/src/plugins/vis_builder/public/application/components/workspace.scss index c06e60607665..1d47dccd0e21 100644 --- a/src/plugins/vis_builder/public/application/components/workspace.scss +++ b/src/plugins/vis_builder/public/application/components/workspace.scss @@ -30,6 +30,7 @@ $keyframe-multiplier: 1 / $animation-multiplier; animation: vbDragAnimation #{$total-duartion}s ease-in-out infinite forwards; position: absolute; top: 34.5%; + width: 50% !important; } } diff --git a/src/plugins/vis_builder/public/application/components/workspace.tsx b/src/plugins/vis_builder/public/application/components/workspace.tsx index 23c9f081fdea..fb1a1d49ee80 100644 --- a/src/plugins/vis_builder/public/application/components/workspace.tsx +++ b/src/plugins/vis_builder/public/application/components/workspace.tsx @@ -93,14 +93,14 @@ export const Workspace: FC = ({ children }) => { body={ <>

Drag a field to the configuration panel to generate a visualization.

- +
- +
} /> From b19c1717a29fffa1b40f8073c6dfb3fb4fe85972 Mon Sep 17 00:00:00 2001 From: Abhishek Reddy <62020972+AbhishekReddy1127@users.noreply.github.com> Date: Mon, 14 Nov 2022 10:45:11 -0800 Subject: [PATCH 21/25] [Vis Builder] Removed Hard Coded Strings and Used i18n to transalte (#2867) Signed-off-by: AbhishekReddy1127 Signed-off-by: AbhishekReddy1127 --- CHANGELOG.md | 1 + .../application/components/data_tab/dropbox.tsx | 7 ++++++- .../public/application/components/workspace.tsx | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2a7f5368714..e0691372f424 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [MD] Refactor data source error handling ([#2661](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2661)) - Refactor and improve Discover field summaries ([#2391](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2391)) +- [Vis Builder] Removed Hard Coded Strings and Used i18n to transalte([#2867](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2867)) ### 🔩 Tests diff --git a/src/plugins/vis_builder/public/application/components/data_tab/dropbox.tsx b/src/plugins/vis_builder/public/application/components/data_tab/dropbox.tsx index f6b7a6ca221b..70b43a2c6014 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/dropbox.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/dropbox.tsx @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { i18n } from '@osd/i18n'; import { EuiButtonIcon, EuiDragDropContext, @@ -127,7 +128,11 @@ const DropboxComponent = ({ } ${canDrop ? 'canDrop' : ''}`} {...(isValidDropTarget && dropProps)} > - Click or drop to add + + {i18n.translate('visBuilder.dropbox.addField.title', { + defaultMessage: 'Click or drop to add', + })} + { ) : ( Add a field to start} + title={ +

+ {i18n.translate('visBuilder.workSpace.empty.title', { + defaultMessage: 'Add a field to start', + })} +

+ } body={ <> -

Drag a field to the configuration panel to generate a visualization.

+

+ {i18n.translate('visBuilder.workSpace.empty.description', { + defaultMessage: + 'Drag a field to the configuration panel to generate a visualization.', + })} +

Date: Fri, 18 Nov 2022 10:53:19 -0800 Subject: [PATCH 22/25] [Doc] Document `charts` plugin (#2695) - Update README with full capabilities - Add `current_usage` to track current usage Signed-off-by: Josh Romero --- CHANGELOG.md | 1 + docs/charts/current_usage.md | 184 +++++++++++++++++++++++++++++++++++ src/plugins/charts/README.md | 81 ++++++++++++--- 3 files changed, 255 insertions(+), 11 deletions(-) create mode 100644 docs/charts/current_usage.md diff --git a/CHANGELOG.md b/CHANGELOG.md index e0691372f424..5ed0d65e7560 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Add the release runbook to RELEASING.md ([#2533](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2533)) - [MD] Add design documents of multiple data source feature [#2538](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2538) - [MD] Tweak multiple data source design doc [#2724](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2724) +- Add `current-usage.md` and more details to `README.md` of `charts` plugin ([#2695](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2695)) ### 🛠 Maintenance diff --git a/docs/charts/current_usage.md b/docs/charts/current_usage.md new file mode 100644 index 000000000000..f3e7db435955 --- /dev/null +++ b/docs/charts/current_usage.md @@ -0,0 +1,184 @@ +# Usage + +The purpose of this doc is to keep track of the current (as of 2022-11-14) usage of the [charts plugin](../../src/plugins/charts/), as well as other packages and tools with similar purposes. See https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2830 for more information on future plans. + +## Lifecycle methods/services + +### `ChartsPluginStart` + +1. `ChartsPluginStart['theme']` used by `discover` plugin to fetch `chartsTheme` and `chartsBaseTheme` for use in styling the histogram. + +### `ChartsPluginSetup` + +1. `ChartsPluginSetup` declared as one of `MetricVisPluginSetupDependencies` in the `vis_type_metric` plugin, but isn't actually used. +2. `ChartsPluginSetup['colors']` used by `vis_type_tagcloud` plugin. Only the seed colors are used via `d3.scale.ordinal().range(colors.seedColors)` +3. `ChartsPluginSetup.colors` and `ChartsPluginSetup.theme` used by the `vis_type_timeseries` plugin. + 1. `themeService.useChartsBaseTheme()` is used only as a fallback; otherwise theme (dark or light) is calculated from the user-specified background color + 2. `colors.mappedColors` used to fetch mapped colors only if user has not specified a color for a particular series label (and there's no color specified from the server). +4. `ChartsPluginSetup.colors.createColorLookupFunction()` is used by the `vis_type_vislib` plugin, ultimately, as part of `getColorFunc()` and `getPieColorFunc()`; the former also uses fallback for default and overwritten colors from `uiState`. +5. Set as a dependency in stub plugin `vis_type_xy`, but not actually used. + +## `uiSettings` in advanced settings `visualization:colorMapping` + +Appears to only be used by the telemetry plugin: https://github.com/opensearch-project/OpenSearch-Dashboards/blob/95f4fd5c6a6cd59bd555bf0ec120843ef6a93566/src/plugins/telemetry/schema/oss_plugins.json#L1363 + +## Static functions and components + +### Color Maps + +#### `ColorMap` interface + +1. `region_map` plugin +2. `tile_map` plugin +3. `timeline` plugin +4. `vis_type_metric` plugin +5. `vis_type_timeline` plugin + +#### `ColorSchema` interface + +1. `maps_legacy` plugin +2. `region_map` plugin +3. `tile_map` plugin +4. `vis_type_metric` plugin +5. `vis_type_vislib` plugin +6. `visualizations` plugin +7. `visualize` plugin +8. `vis_builder` plugin + +#### `ColorSchemas` enum + +1. `region_map` plugin +2. `tile_map` plugin +3. `vis_type_metric` plugin +4. `vis_type_vislib` plugin +5. `vis_builder` plugin + +#### `RawColorSchema` interface + +Not used by any core plugins + +#### `colorSchemas` array of objects + +1. `region_map` plugin +2. `tile_map` plugin +3. `vis_type_metric` plugin +4. `vis_type_vislib` plugin +5. `vis_builder` plugin + +#### `getHeatmapColors` function + +1. `vis_type_metric` plugin +2. `vis_type_vislib` plugin + +#### `truncatedColorMaps` object + +1. `region_map` plugin +2. `tile_map` plugin + +#### `truncatedColorSchemas` array of objects + +1. `region_map` plugin +2. `tile_map` plugin + +#### `vislibColorMaps` object + +1. `vis_type_metric` plugin + +### React components + +These components may eventually make more sense elsewhere. See https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2832 for one such proposal. + +#### `ColorModes` object + +1. `vis_type_metric` plugin +2. `vis_type_vislib` plugin +3. `vis_builder` plugin + +#### `Rotates` object + +1. `vis_type_vislib` plugin + +#### `BasicOptions` component + +1. `tile_map` plugin +2. `vis_type_vislib` plugin +3. `vis_builder` plugin + +#### `ColorRanges` component + +1. `vis_type_metric` plugin +2. `vis_type_vislib` plugin +3. `vis_builder` plugin + +#### `ColorSchemaOptions` component + +Accounts for customized `vis.colors` in the `uiState`. Supports setting custom colors via legend, and resetting. + +1. `vis_type_metric` plugin. Doesn't actually support custom colors +2. `vis_type_vislib` plugin +3. `vis_builder` plugin (metric visualization). Doesn't support custom colors + +#### `NumberInputOption` component + +1. `region_map` plugin +2. `vis_type_table` plugin +3. `vis_type_vislib` plugin + +#### `RangeOption` component + +1. `tile_map` plugin +2. `vis_type_markdown` plugin +3. `vis_type_metric` plugin +4. `vis_type_timeseries` plugin +5. `vis_builder` plugin + +#### `RequiredNumberInputOption` component + +1. `vis_type_vislib` plugin + +#### `SelectOption` component + +1. `index_pattern_management` plugin +2. `maps_legacy` plugin +3. `region_map` plugin +4. `tile_map` plugin +5. `vis_type_table` plugin +6. `vis_type_tagcloud` plugin +7. `vis_type_timeseries` plugin +8. `vis_type_vislib` plugin +9. `vis_builder` plugin + +#### `SwitchOption` component + +1. `maps_legacy` plugin +2. `region_map` plugin +3. `tile_map` plugin +4. `vis_type_markdown` plugin +5. `vis_type_metric` plugin +6. `vis_type_table` plugin +7. `vis_type_tagcloud` plugin +8. `vis_type_vislib` plugin +9. `vis_builder` plugin + +#### `TextInputOption` component + +1. `maps_legacy` plugin +2. `vis_type_vislib` plugin + +# OUI chart colors + +An alternative to using color schemas and maps provided by the `charts` plugin is to use [color palettes from OUI](https://github.com/opensearch-project/oui/blob/main/src/services/color/oui_palettes.ts). + +## `ouiPaletteColorBlind()` + +1. `index_pattern_management` plugin +2. `vis_type_vega` plugin +3. `vis_type_vislib` plugin + +## Other quantitative palettes + +Not currently used + +## `colorPalette` + +Not currently used diff --git a/src/plugins/charts/README.md b/src/plugins/charts/README.md index f7ff405c74f2..1afd049ea284 100644 --- a/src/plugins/charts/README.md +++ b/src/plugins/charts/README.md @@ -1,29 +1,88 @@ # Charts -The Charts plugin is a way to create easier integration of shared colors, themes, types and other utilities across all OpenSearch Dashboards charts and visualizations. +The Charts plugin provides utility services for accessing shared colors and themes for visual consistency across all OpenSearch Dashboards charts and visualizations. It also provides a number of static utility functions and standard components for user-specified chart configuration. -## Static methods +## Services -### `vislibColorMaps` +### Theme service -Color mappings related to vislib visualizations +A utility service for fetching `chartsTheme` and `chartsBaseTheme`. -### `truncatedColorMaps` +For more, see Theme service [docs](public/services/theme/README.md) -Color mappings subset of `vislibColorMaps` +### Color service +#### Static properties +##### `seedColors` + +A list of colors chosen for visual appeal. + +#### Static methods +##### `mappedColors` -### `colorSchemas` +Get a value-based mapping of colors. + +##### `createColorLookupFunction` + +Factory for color mapping function. + +## Static functions and components +### Color maps +#### `colorSchemas` Color mappings in `value`/`text` form -### `getHeatmapColors` +#### `getHeatmapColors` Function to retrieve heatmap related colors based on `value` and `colorSchemaName` -### `truncatedColorSchemas` +#### `truncatedColorMaps` + +Color mappings subset of `vislibColorMaps` + +#### `truncatedColorSchemas` Truncated color mappings in `value`/`text` form -## Theme +#### `vislibColorMaps` + +Color mappings related to vislib visualizations + +### Components + +Standardized React input UI components which can be used by visualization editors to specify various visualization options. + +#### `BasicOptions` + +Components for specifying legend and tooltip + +#### `ColorRanges` + +Component for specifying color range thresholds + +#### `ColorSchemaOptions` + +Component for specifying color schemas (palettes) + +#### `NumberInputOption` + +Deprecated in favor of `RequiredNumberInputOption` + +#### `RangeOption` + +Component for specifying a numerical value with a slider + +#### `RequiredNumberInputOption` + +Component for specifying numerical values, such as a threshold. + +#### `SelectOption` + +Basic select component + +#### `SwitchOption` + +Basic toggle component + +#### `TextInputOption` -See Theme service [docs](public/services/theme/README.md) +Basic text input component From ab98411c5becd41ed54813fd838b487980ed9ef0 Mon Sep 17 00:00:00 2001 From: Manasvini B Suryanarayana Date: Fri, 18 Nov 2022 11:51:42 -0800 Subject: [PATCH 23/25] Setup OpenSearch plugin dependencies on cluster snapshot (#2734) * Adding yarn opensearch args to setup opensearch plugin dependencies on snapshot * Updating the example opensearch snapshot help command with --P arg * Adding tests to the plugin installation function * Adding documentation for the new flag in developer guide Signed-off-by: Manasvini B Suryanarayana --- CHANGELOG.md | 1 + DEVELOPER_GUIDE.md | 24 +++++++++++++++++ .../src/cli_commands/snapshot.js | 10 ++++++- packages/osd-opensearch/src/cluster.js | 25 ++++++++++++++++- .../src/integration_tests/cluster.test.js | 27 +++++++++++++++++++ packages/osd-opensearch/src/paths.js | 1 + 6 files changed, 86 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ed0d65e7560..952729f7784e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Save Object Aggregation View] Fix for export all after scroll count response changed in PR#2656 ([#2696](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2696)) - [Vis Builder] Add an experimental table visualization in vis builder ([#2705](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2705)) - [Vis Builder] Add field summary popovers ([#2682](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2682)) +- Add yarn opensearch arg to setup plugin dependencies ([#2544](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2544)) ### 🐛 Bug Fixes diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 4dc3e0d2583e..4fe8fc4e368c 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -59,6 +59,30 @@ Dashboards. In a separate terminal you can run the latest snapshot built using: $ yarn opensearch snapshot ``` +If you would like to download a specific OpenSearch plugin on the cluster snapshot, pass the `--P` flag after `yarn opensearch snapshot`. We can use the flag multiple times to install multiple plugins on the cluster snapshot. The argument value can be URL to the plugin's zip file, maven coordinates of the plugin or for local zip files, use `file:` followed by the absolute or relative path to the plugin zip file. Below is the example help command: + +``` +$ yarn opensearch snapshot --P https://repo1.maven.org/maven2/org/opensearch/plugin/opensearch-test-plugin/2.4.0.0/opensearch-test-plugin-2.4.0.0.zip +``` + +Following are the list of options that can be passed after `yarn opensearch snapshot` to configure the cluster snapshot. +Options: + + --license Run with a 'oss', 'basic', or 'trial' license [default: oss] + --version Version of OpenSearch to download [default: 3.0.0}] + --base-path Path containing cache/installations [default: /home/ubuntu/OpenSearch-Dashboards/.opensearch] + --install-path Installation path, defaults to 'source' within base-path + --data-archive Path to zip or tarball containing an OpenSearch data directory to seed the cluster with. + --password Sets password for opensearch user [default: changeme] + -E Additional key=value settings to pass to OpenSearch + --download-only Download the snapshot but don't actually start it + --ssl Sets up SSL on OpenSearch + --P OpenSearch plugin artifact URL to install it on the cluster. + +``` +$ yarn opensearch snapshot --version 2.2.0 -E cluster.name=test -E path.data=/tmp/opensearch-data --P org.opensearch.plugin:test-plugin:2.2.0.0 --P file:/home/user/opensearch-test-plugin-2.2.0.0.zip +``` + **Warning:** Starting the Dashboards instance before or during the initialization of the OpenSearch Server can cause Dashboards to sometimes misbehave. Ensure that the OpenSearch server instance is up and running first before starting up the Dashboards dev server from the next step. ### Run OpenSearch Dashboards diff --git a/packages/osd-opensearch/src/cli_commands/snapshot.js b/packages/osd-opensearch/src/cli_commands/snapshot.js index 99b85b7439a9..3cf8701856bd 100644 --- a/packages/osd-opensearch/src/cli_commands/snapshot.js +++ b/packages/osd-opensearch/src/cli_commands/snapshot.js @@ -49,10 +49,13 @@ exports.help = (defaults = {}) => { -E Additional key=value settings to pass to OpenSearch --download-only Download the snapshot but don't actually start it --ssl Sets up SSL on OpenSearch + --P OpenSearch plugin artifact URL to install it on the cluster. We can use the flag multiple times + to install multiple plugins on the cluster snapshot. The argument value can be url to zip file, maven coordinates of the plugin + or for local zip files, use file:. Example: - opensearch snapshot --version 5.6.8 -E cluster.name=test -E path.data=/tmp/opensearch-data + opensearch snapshot --version 2.2.0 -E cluster.name=test -E path.data=/tmp/opensearch-data --P org.opensearch.plugin:test-plugin:2.2.0.0 --P file:/home/user/opensearch-test-plugin-2.2.0.0.zip `; }; @@ -64,6 +67,7 @@ exports.run = async (defaults = {}) => { installPath: 'install-path', dataArchive: 'data-archive', opensearchArgs: 'E', + opensearchPlugins: 'P', }, string: ['version'], @@ -83,6 +87,10 @@ exports.run = async (defaults = {}) => { await cluster.extractDataDirectory(installPath, options.dataArchive); } + if (options.opensearchPlugins) { + await cluster.installOpenSearchPlugins(installPath, options.opensearchPlugins); + } + options.bundledJDK = true; await cluster.run(installPath, options); diff --git a/packages/osd-opensearch/src/cluster.js b/packages/osd-opensearch/src/cluster.js index b4912d677359..3527668eed05 100644 --- a/packages/osd-opensearch/src/cluster.js +++ b/packages/osd-opensearch/src/cluster.js @@ -34,7 +34,7 @@ const execa = require('execa'); const chalk = require('chalk'); const path = require('path'); const { downloadSnapshot, installSnapshot, installSource, installArchive } = require('./install'); -const { OPENSEARCH_BIN } = require('./paths'); +const { OPENSEARCH_BIN, OPENSEARCH_PLUGIN } = require('./paths'); const { log: defaultLog, parseOpenSearchLog, extractConfigFiles, decompress } = require('./utils'); const { createCliError } = require('./errors'); const { promisify } = require('util'); @@ -170,6 +170,29 @@ exports.Cluster = class Cluster { this._log.indent(-4); } + /** + * Unpacks a tar or zip file containing the OpenSearch plugin directory for an + * OpenSearch cluster. + * + * @param {string} installPath + * @param {Array|string} opensearchPlugins Array or string of OpenSearch plugin(s) artifact url + */ + async installOpenSearchPlugins(installPath, opensearchPluginsPath) { + if (opensearchPluginsPath) { + this._log.info(chalk.bold(`Downloading OpenSearch plugin(s) on the cluster snapshot`)); + this._log.indent(4); + opensearchPluginsPath = + typeof opensearchPluginsPath === 'string' ? [opensearchPluginsPath] : opensearchPluginsPath; + // Run opensearch-plugin tool script to download OpenSearch plugin artifacts + for (const pluginPath of opensearchPluginsPath) { + this._log.info(`Installing OpenSearch Plugin from the path: ${pluginPath}`); + await execa(OPENSEARCH_PLUGIN, [`install`, `--batch`, pluginPath], { cwd: installPath }); + } + this._log.info(`Plugin installation complete`); + this._log.indent(-4); + } + } + /** * Starts OpenSearch and returns resolved promise once started * diff --git a/packages/osd-opensearch/src/integration_tests/cluster.test.js b/packages/osd-opensearch/src/integration_tests/cluster.test.js index 43a8f0f63c7b..7b4105aefd49 100644 --- a/packages/osd-opensearch/src/integration_tests/cluster.test.js +++ b/packages/osd-opensearch/src/integration_tests/cluster.test.js @@ -292,6 +292,33 @@ describe('#start(installPath)', () => { }); }); +describe('#installOpenSearchPlugins()', () => { + it('install array of plugins on cluster snapshot', async () => { + const cluster = new Cluster({ log }); + await cluster.installOpenSearchPlugins('foo', ['foo1', 'foo2']); + expect(execa).toHaveBeenCalledTimes(2); + expect(execa).toHaveBeenCalledWith('./bin/opensearch-plugin', ['install', '--batch', 'foo1'], { + cwd: 'foo', + }); + expect(execa).toHaveBeenCalledWith('./bin/opensearch-plugin', ['install', '--batch', 'foo2'], { + cwd: 'foo', + }); + }); + it('installs single plugin on cluster snapshot', async () => { + const cluster = new Cluster({ log }); + await cluster.installOpenSearchPlugins('foo', 'foo1'); + expect(execa).toHaveBeenCalledTimes(1); + expect(execa).toHaveBeenCalledWith('./bin/opensearch-plugin', ['install', '--batch', 'foo1'], { + cwd: 'foo', + }); + }); + it('do not execute plugin installation script when no plugins in the param list', async () => { + const cluster = new Cluster({ log }); + await cluster.installOpenSearchPlugins('foo'); + expect(execa).toHaveBeenCalledTimes(0); + }); +}); + describe('#run()', () => { it('resolves when bin/opensearch exists with 0', async () => { mockOpenSearchBin({ exitCode: 0 }); diff --git a/packages/osd-opensearch/src/paths.js b/packages/osd-opensearch/src/paths.js index e278f20fc5ab..93bb80e97ff1 100644 --- a/packages/osd-opensearch/src/paths.js +++ b/packages/osd-opensearch/src/paths.js @@ -44,3 +44,4 @@ exports.OPENSEARCH_BIN = maybeUseBat('bin/opensearch'); exports.OPENSEARCH_CONFIG = 'config/opensearch.yml'; exports.OPENSEARCH_KEYSTORE_BIN = maybeUseBat('./bin/opensearch-keystore'); +exports.OPENSEARCH_PLUGIN = maybeUseBat('./bin/opensearch-plugin'); From 9377fbb1e86012dcf4d995ece3a2da191bdba82b Mon Sep 17 00:00:00 2001 From: Anan Zhuang Date: Mon, 21 Nov 2022 11:01:37 -0800 Subject: [PATCH 24/25] [WS-2021-0638][Security] bump mocha to 10.1.0 (#2711) * [WS-2021-0638][Security] bump mocha to 10.1.0 In our current repo, most mocha tests have been changed to jest in this issue: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/215 The fix for the above issue (https://github.com/mochajs/mocha/commit/61b4b9209c2c64b32c8d48b1761c3b9384d411ea) is only released in the latest version v10.1.0: https://github.com/mochajs/mocha/blob/5f96d511dbf913f135b92198aab721a27f6b44fe/lib/utils.js#L79 Since we are considering this change might break others, we will not backport to 2.x and release it in 3.0.0 Issue Resolved: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2269 Signed-off-by: Anan Zhuang --- CHANGELOG.md | 1 + package.json | 2 +- .../integration/failure_hooks.test.js | 1 + .../lib/mocha/filter_suites_by_tags.test.js | 26 +- yarn.lock | 432 +++++++----------- 5 files changed, 184 insertions(+), 278 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 952729f7784e..3a946298b911 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -109,6 +109,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Resolve sub-dependent d3-color version and potential security issue ([#2454](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2454)) - [CVE-2022-3517] Bumps minimatch from 3.0.4 to 3.0.5 and [IBM X-Force ID: 220063] unset-value from 1.0.1 to 2.0.1 ([#2640](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2640)) - [CVE-2022-37601] Bump loader-utils to 2.0.3 ([#2689](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2689)) +- [WS-2021-0638][Security] bump mocha to 10.1.0 ([#2711](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2711)) ### 📈 Features/Enhancements diff --git a/package.json b/package.json index f74e858b68c3..77b27025dd0f 100644 --- a/package.json +++ b/package.json @@ -408,7 +408,7 @@ "load-grunt-config": "^4.0.1", "load-json-file": "^6.2.0", "markdown-it": "^12.3.2", - "mocha": "^7.2.0", + "mocha": "10.1.0", "mock-fs": "^4.12.0", "monaco-editor": "~0.17.0", "ms-chromium-edge-driver": "^0.4.3", diff --git a/packages/osd-test/src/functional_test_runner/integration/failure_hooks.test.js b/packages/osd-test/src/functional_test_runner/integration/failure_hooks.test.js index 2047a6c3065f..9e565671ba5d 100644 --- a/packages/osd-test/src/functional_test_runner/integration/failure_hooks.test.js +++ b/packages/osd-test/src/functional_test_runner/integration/failure_hooks.test.js @@ -55,6 +55,7 @@ describe('failure hooks', function () { { flag: '$FAILING_TEST$', assert(lines) { + expect(lines.shift()).to.match(/\$FAILING_TEST\$/); expect(lines.shift()).to.match(/global before each/); expect(lines.shift()).to.match(/info\s+testFailure\s+\$FAILING_TEST_ERROR\$/); expect(lines.shift()).to.match(/info\s+testFailureAfterDelay\s+\$FAILING_TEST_ERROR\$/); diff --git a/packages/osd-test/src/functional_test_runner/lib/mocha/filter_suites_by_tags.test.js b/packages/osd-test/src/functional_test_runner/lib/mocha/filter_suites_by_tags.test.js index 5781a6fd785f..bc27ff7e1a8a 100644 --- a/packages/osd-test/src/functional_test_runner/lib/mocha/filter_suites_by_tags.test.js +++ b/packages/osd-test/src/functional_test_runner/lib/mocha/filter_suites_by_tags.test.js @@ -111,8 +111,8 @@ it('only runs hooks of parents and tests in level1a', async () => { "suite: ", "suite: level 1", "suite: level 1 level 1a", - "hook: \\"before each\\" hook: rootBeforeEach", - "hook: level 1 \\"before each\\" hook: level1BeforeEach", + "hook: \\"before each\\" hook: rootBeforeEach for \\"test 1a\\"", + "hook: level 1 \\"before each\\" hook: level1BeforeEach for \\"test 1a\\"", "test: level 1 level 1a test 1a", ] `); @@ -130,8 +130,8 @@ it('only runs hooks of parents and tests in level1b', async () => { "suite: ", "suite: level 1", "suite: level 1 level 1b", - "hook: \\"before each\\" hook: rootBeforeEach", - "hook: level 1 \\"before each\\" hook: level1BeforeEach", + "hook: \\"before each\\" hook: rootBeforeEach for \\"test 1b\\"", + "hook: level 1 \\"before each\\" hook: level1BeforeEach for \\"test 1b\\"", "test: level 1 level 1b test 1b", ] `); @@ -149,12 +149,12 @@ it('only runs hooks of parents and tests in level1a and level1b', async () => { "suite: ", "suite: level 1", "suite: level 1 level 1a", - "hook: \\"before each\\" hook: rootBeforeEach", - "hook: level 1 \\"before each\\" hook: level1BeforeEach", + "hook: \\"before each\\" hook: rootBeforeEach for \\"test 1a\\"", + "hook: level 1 \\"before each\\" hook: level1BeforeEach for \\"test 1a\\"", "test: level 1 level 1a test 1a", "suite: level 1 level 1b", - "hook: \\"before each\\" hook: rootBeforeEach", - "hook: level 1 \\"before each\\" hook: level1BeforeEach", + "hook: \\"before each\\" hook: rootBeforeEach for \\"test 1b\\"", + "hook: level 1 \\"before each\\" hook: level1BeforeEach for \\"test 1b\\"", "test: level 1 level 1b test 1b", ] `); @@ -173,8 +173,8 @@ it('only runs level1a if including level1 and excluding level1b', async () => { "suite: ", "suite: level 1", "suite: level 1 level 1a", - "hook: \\"before each\\" hook: rootBeforeEach", - "hook: level 1 \\"before each\\" hook: level1BeforeEach", + "hook: \\"before each\\" hook: rootBeforeEach for \\"test 1a\\"", + "hook: level 1 \\"before each\\" hook: level1BeforeEach for \\"test 1a\\"", "test: level 1 level 1a test 1a", ] `); @@ -193,8 +193,8 @@ it('only runs level1b if including level1 and excluding level1a', async () => { "suite: ", "suite: level 1", "suite: level 1 level 1b", - "hook: \\"before each\\" hook: rootBeforeEach", - "hook: level 1 \\"before each\\" hook: level1BeforeEach", + "hook: \\"before each\\" hook: rootBeforeEach for \\"test 1b\\"", + "hook: level 1 \\"before each\\" hook: level1BeforeEach for \\"test 1b\\"", "test: level 1 level 1b test 1b", ] `); @@ -212,7 +212,7 @@ it('only runs level2 if excluding level1', async () => { "suite: ", "suite: level 2", "suite: level 2 level 2a", - "hook: \\"before each\\" hook: rootBeforeEach", + "hook: \\"before each\\" hook: rootBeforeEach for \\"test 2a\\"", "test: level 2 level 2a test 2a", ] `); diff --git a/yarn.lock b/yarn.lock index d98a153726af..e3d69def9d6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4417,10 +4417,10 @@ angular@>=1.0.6, angular@^1.8.2: resolved "https://registry.yarnpkg.com/angular/-/angular-1.8.2.tgz#5983bbb5a9fa63e213cb7749199e0d352de3a2f1" integrity sha512-IauMOej2xEe7/7Ennahkbb5qd/HFADiNuLSESz9Q27inmi32zB0lnAsFeLEWcox3Gd1F6YhNd1CP7/9IukJ0Gw== -ansi-colors@3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" - integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== ansi-colors@^1.0.1: version "1.1.0" @@ -4505,7 +4505,7 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -anymatch@^3.0.0, anymatch@^3.0.3, anymatch@~3.1.1, anymatch@~3.1.2: +anymatch@^3.0.0, anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== @@ -5565,7 +5565,7 @@ camelcase@^5.0.0, camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.2.0: +camelcase@^6.0.0, camelcase@^6.2.0: version "6.3.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== @@ -5727,22 +5727,7 @@ cheerio@^1.0.0-rc.3: parse5-htmlparser2-tree-adapter "^6.0.1" tslib "^2.2.0" -chokidar@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" - integrity sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.2.0" - optionalDependencies: - fsevents "~2.1.1" - -"chokidar@>=2.0.0 <4.0.0", chokidar@^3.4.0, chokidar@^3.4.1, chokidar@^3.4.2: +chokidar@3.5.3, "chokidar@>=2.0.0 <4.0.0", chokidar@^3.4.0, chokidar@^3.4.1, chokidar@^3.4.2: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -5887,15 +5872,6 @@ cli-width@^3.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -6852,13 +6828,6 @@ debug@3.1.0: dependencies: ms "2.0.0" -debug@3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - debug@3.X, debug@^3.2.6, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -6866,7 +6835,7 @@ debug@3.X, debug@^3.2.6, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@4, debug@^4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: +debug@4, debug@4.3.4, debug@^4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -6905,6 +6874,11 @@ decamelize@^1.1.0, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + decimal.js@^10.2.1: version "10.3.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" @@ -6994,7 +6968,7 @@ defer-to-connect@^2.0.0: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== -define-properties@^1.1.2, define-properties@^1.1.3: +define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== @@ -7206,7 +7180,12 @@ diff-sequences@^27.5.1: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== -diff@3.5.0, diff@^3.5.0: +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +diff@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== @@ -7857,7 +7836,12 @@ escalade@^3.0.2, escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= @@ -7867,11 +7851,6 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - escodegen@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" @@ -8712,12 +8691,13 @@ find-root@^1.1.0: resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== -find-up@3.0.0, find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: - locate-path "^3.0.0" + locate-path "^6.0.0" + path-exists "^4.0.0" find-up@^2.1.0: version "2.1.0" @@ -8726,6 +8706,13 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -8784,12 +8771,10 @@ flat-cache@^3.0.4: flatted "^3.1.0" rimraf "^3.0.2" -flat@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.1.tgz#a392059cc382881ff98642f5da4dde0a959f309b" - integrity sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA== - dependencies: - is-buffer "~2.0.3" +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== flatstr@^1.0.12: version "1.0.12" @@ -9007,11 +8992,6 @@ fsevents@^2.3.2, fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -fsevents@~2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== - function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -9189,7 +9169,7 @@ glob-all@^3.2.1: glob "^7.1.2" yargs "^15.3.1" -glob-parent@^3.1.0, glob-parent@^5.0.0, glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@^6.0.0, glob-parent@~5.1.0, glob-parent@~5.1.2: +glob-parent@^3.1.0, glob-parent@^5.0.0, glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@^6.0.0, glob-parent@~5.1.2: version "6.0.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== @@ -9222,18 +9202,6 @@ glob-to-regexp@^0.4.0, glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@7.1.7, glob@~7.1.6: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" @@ -9246,7 +9214,7 @@ glob@7.1.7, glob@~7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7, glob@^7.2.0: +glob@7.2.0, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7, glob@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -9416,11 +9384,6 @@ graceful-fs@4.X, graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, g resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - grunt-available-tasks@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/grunt-available-tasks/-/grunt-available-tasks-0.6.3.tgz#5be7f6fdda776b80a7b272a21f68bd3050f82260" @@ -9663,7 +9626,7 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" -has-symbols@^1.0.0, has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== @@ -10457,7 +10420,7 @@ is-buffer@^1.1.4, is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-buffer@^2.0.0, is-buffer@~2.0.3: +is-buffer@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== @@ -10688,7 +10651,7 @@ is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= -is-plain-obj@^2.0.0: +is-plain-obj@^2.0.0, is-plain-obj@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== @@ -11524,14 +11487,6 @@ js-yaml-js-types@1.0.0: dependencies: esprima "^4.0.1" -js-yaml@3.13.1, js-yaml@~3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - js-yaml@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -11547,6 +11502,14 @@ js-yaml@^3.13.1, js-yaml@^3.14.0, js-yaml@~3.14.0: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@~3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + jsbn@1.1.0, jsbn@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" @@ -12055,6 +12018,13 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash-es@^4.17.15: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" @@ -12248,12 +12218,13 @@ log-ok@^0.1.1: ansi-green "^0.1.1" success-symbol "^0.1.0" -log-symbols@3.0.0, log-symbols@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" - integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== +log-symbols@4.1.0, log-symbols@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== dependencies: - chalk "^2.4.2" + chalk "^4.1.0" + is-unicode-supported "^0.1.0" log-symbols@^1.0.2: version "1.0.2" @@ -12269,13 +12240,12 @@ log-symbols@^2.2.0: dependencies: chalk "^2.0.1" -log-symbols@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== +log-symbols@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" + integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" + chalk "^2.4.2" log-update@^2.3.0: version "2.3.0" @@ -12702,7 +12672,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.2, minimatch@~3.0.4: +"minimatch@2 || 3", minimatch@5.0.1, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.2, minimatch@~3.0.4: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -12788,13 +12758,6 @@ mkdirp-classic@^0.5.2: resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -mkdirp@0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - mkdirp@^0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" @@ -12812,35 +12775,32 @@ mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mocha@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.2.0.tgz#01cc227b00d875ab1eed03a75106689cfed5a604" - integrity sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ== +mocha@10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.1.0.tgz#dbf1114b7c3f9d0ca5de3133906aea3dfc89ef7a" + integrity sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg== dependencies: - ansi-colors "3.2.3" + ansi-colors "4.1.1" browser-stdout "1.3.1" - chokidar "3.3.0" - debug "3.2.6" - diff "3.5.0" - escape-string-regexp "1.0.5" - find-up "3.0.0" - glob "7.1.3" - growl "1.10.5" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" he "1.2.0" - js-yaml "3.13.1" - log-symbols "3.0.0" - minimatch "3.0.4" - mkdirp "0.5.5" - ms "2.1.1" - node-environment-flags "1.0.6" - object.assign "4.1.0" - strip-json-comments "2.0.1" - supports-color "6.0.0" - which "1.3.1" - wide-align "1.1.3" - yargs "13.3.2" - yargs-parser "13.1.2" - yargs-unparser "1.6.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" mock-fs@^4.12.0: version "4.14.0" @@ -12918,17 +12878,12 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -12998,6 +12953,11 @@ nano-css@^5.2.1: stacktrace-js "^2.0.2" stylis "^4.0.6" +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== + nanoid@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557" @@ -13115,14 +13075,6 @@ node-emoji@^1.10.0: dependencies: lodash "^4.17.21" -node-environment-flags@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" - integrity sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw== - dependencies: - object.getownpropertydescriptors "^2.0.3" - semver "^5.7.0" - node-fetch@^2.3.0, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -13438,7 +13390,7 @@ object-is@^1.0.2, object-is@^1.1.2, object-is@^1.1.4, object-is@^1.1.5: call-bind "^1.0.2" define-properties "^1.1.3" -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: +object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== @@ -13450,16 +13402,6 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - object.assign@^4.0.4, object.assign@^4.1.0, object.assign@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" @@ -13508,15 +13450,6 @@ object.fromentries@^2.0.3, object.fromentries@^2.0.5: define-properties "^1.1.3" es-abstract "^1.19.1" -object.getownpropertydescriptors@^2.0.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" - integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - object.hasown@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" @@ -13744,6 +13677,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-map@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" @@ -15012,13 +14952,6 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" -readdirp@~3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" - integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ== - dependencies: - picomatch "^2.0.4" - readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -15782,6 +15715,13 @@ semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@~7.3.0: dependencies: lru-cache "^6.0.0" +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + serialize-javascript@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" @@ -16422,14 +16362,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -16439,7 +16371,15 @@ string-width@^1.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^3.0.0, string-width@^3.1.0: +string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== @@ -16561,7 +16501,7 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: +strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== @@ -16607,16 +16547,16 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -strip-json-comments@^3.0.1, strip-json-comments@^3.1.1, strip-json-comments@~3.1.1: +strip-json-comments@3.1.1, strip-json-comments@^3.0.1, strip-json-comments@^3.1.1, strip-json-comments@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + strong-log-transformer@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" @@ -16792,12 +16732,12 @@ supertest@^6.2.2: methods "^1.1.2" superagent "^7.1.0" -supports-color@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" - integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== +supports-color@8.1.1, supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: - has-flag "^3.0.0" + has-flag "^4.0.0" supports-color@^0.2.0: version "0.2.0" @@ -16823,13 +16763,6 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - supports-hyperlinks@^2.0.0, supports-hyperlinks@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" @@ -18719,7 +18652,7 @@ which-typed-array@^1.1.2: has-tostringtag "^1.0.0" is-typed-array "^1.1.7" -which@1.3.1, which@^1.2.14, which@^1.2.9, which@^1.3.1: +which@^1.2.14, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -18733,13 +18666,6 @@ which@^2.0.1, which@^2.0.2, which@~2.0.2: dependencies: isexe "^2.0.0" -wide-align@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - wide-align@^1.1.0: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" @@ -18776,6 +18702,11 @@ worker-farm@^1.7.0: dependencies: errno "~0.1.7" +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== + wrap-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" @@ -18784,15 +18715,6 @@ wrap-ansi@^3.0.1: string-width "^2.1.1" strip-ansi "^4.0.0" -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -18982,13 +18904,10 @@ yaml@^2.0.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec" integrity sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw== -yargs-parser@13.1.2, yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== yargs-parser@^18.1.2, yargs-parser@^18.1.3: version "18.1.3" @@ -19003,30 +18922,28 @@ 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-unparser@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" - integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== dependencies: - flat "^4.1.0" - lodash "^4.17.15" - yargs "^13.3.0" + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" -yargs@13.3.2, yargs@^13.3.0: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== +yargs@16.2.0, yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" yargs@^15.0.2, yargs@^15.3.1: version "15.4.1" @@ -19045,19 +18962,6 @@ yargs@^15.0.2, yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - yargs@~16.0.3: version "16.0.3" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.0.3.tgz#7a919b9e43c90f80d4a142a89795e85399a7e54c" From 9041a8278739e2979cdf6b2307629f3f3b802dcd Mon Sep 17 00:00:00 2001 From: Daniel Belmes <3631206+DanielBelmes@users.noreply.github.com> Date: Mon, 21 Nov 2022 11:26:29 -0800 Subject: [PATCH 25/25] OSD-2847 bump del version to fix race condition (#2873) * OSD-2847 bump del version to fix race condition Signed-off-by: Daniel Belmes <3631206+DanielBelmes@users.noreply.github.com> --- CHANGELOG.md | 1 + package.json | 2 +- packages/osd-i18n/package.json | 2 +- packages/osd-interpreter/package.json | 2 +- packages/osd-monaco/package.json | 2 +- packages/osd-opensearch/package.json | 4 ++-- packages/osd-optimizer/package.json | 2 +- packages/osd-plugin-helpers/package.json | 2 +- packages/osd-pm/package.json | 2 +- packages/osd-test/package.json | 2 +- packages/osd-ui-shared-deps/package.json | 2 +- yarn.lock | 14 ++++++++++++++ 12 files changed, 26 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a946298b911..4c656898be70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Table Visualization] Fix first column sort issue ([#2828](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2828)) - Temporary workaround for task-kill exceptions on Windows when it is passed a pid for a process that is already dead ([#2842](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2842)) - [Vis Builder] Fix empty workspace animation does not work in firefox ([#2853](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2853)) +- Bumped `del` version to fix MacOS race condition ([#2847](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2873)) ### 🚞 Infrastructure diff --git a/package.json b/package.json index 77b27025dd0f..e41ae70451e7 100644 --- a/package.json +++ b/package.json @@ -161,7 +161,7 @@ "commander": "^3.0.2", "core-js": "^3.6.5", "deep-freeze-strict": "^1.1.1", - "del": "^5.1.0", + "del": "^6.1.1", "dns-sync": "^0.2.1", "elastic-apm-node": "^3.7.0", "elasticsearch": "^16.7.0", diff --git a/packages/osd-i18n/package.json b/packages/osd-i18n/package.json index e3acaba58604..98b3f9bbde1d 100644 --- a/packages/osd-i18n/package.json +++ b/packages/osd-i18n/package.json @@ -18,7 +18,7 @@ "@osd/dev-utils": "1.0.0", "@types/intl-relativeformat": "^2.1.0", "@types/react-intl": "^2.3.15", - "del": "^5.1.0", + "del": "^6.1.1", "getopts": "^2.2.5", "supports-color": "^7.0.0", "typescript": "4.0.2" diff --git a/packages/osd-interpreter/package.json b/packages/osd-interpreter/package.json index c8de5349c64f..4654b73b186e 100644 --- a/packages/osd-interpreter/package.json +++ b/packages/osd-interpreter/package.json @@ -24,7 +24,7 @@ "babel-loader": "^8.2.3", "copy-webpack-plugin": "^6.0.2", "css-loader": "^5.2.7", - "del": "^5.1.0", + "del": "^6.1.1", "getopts": "^2.2.5", "pegjs": "0.10.0", "sass-loader": "^10.2.0", diff --git a/packages/osd-monaco/package.json b/packages/osd-monaco/package.json index 8754663f891c..e937b1e8f60b 100644 --- a/packages/osd-monaco/package.json +++ b/packages/osd-monaco/package.json @@ -17,7 +17,7 @@ "@osd/dev-utils": "1.0.0", "babel-loader": "^8.2.3", "css-loader": "^5.2.7", - "del": "^5.1.0", + "del": "^6.1.1", "raw-loader": "^4.0.2", "supports-color": "^7.0.0", "typescript": "4.0.2", diff --git a/packages/osd-opensearch/package.json b/packages/osd-opensearch/package.json index d086033f7288..c2e52d8230a8 100644 --- a/packages/osd-opensearch/package.json +++ b/packages/osd-opensearch/package.json @@ -17,7 +17,7 @@ "abort-controller": "^3.0.0", "chalk": "^4.1.0", "dedent": "^0.7.0", - "del": "^5.1.0", + "del": "^6.1.1", "execa": "^4.0.2", "getopts": "^2.2.5", "glob": "^7.1.7", @@ -30,6 +30,6 @@ "devDependencies": { "@osd/babel-preset": "1.0.0", "@babel/cli": "^7.16.0", - "del": "^5.1.0" + "del": "^6.1.1" } } diff --git a/packages/osd-optimizer/package.json b/packages/osd-optimizer/package.json index e3ffe9a4930a..98c9e2e34fe0 100644 --- a/packages/osd-optimizer/package.json +++ b/packages/osd-optimizer/package.json @@ -23,7 +23,7 @@ "cpy": "^8.0.0", "core-js": "^3.6.5", "dedent": "^0.7.0", - "del": "^5.1.0", + "del": "^6.1.1", "execa": "^4.0.2", "fibers": "^5.0.3", "jest-diff": "^27.5.1", diff --git a/packages/osd-plugin-helpers/package.json b/packages/osd-plugin-helpers/package.json index 6868d0ae6137..7ee45578a63b 100644 --- a/packages/osd-plugin-helpers/package.json +++ b/packages/osd-plugin-helpers/package.json @@ -19,7 +19,7 @@ "@osd/cross-platform": "1.0.0", "@osd/dev-utils": "1.0.0", "@osd/optimizer": "1.0.0", - "del": "^5.1.0", + "del": "^6.1.1", "execa": "^4.0.2", "gulp-zip": "^5.0.2", "inquirer": "^7.3.3", diff --git a/packages/osd-pm/package.json b/packages/osd-pm/package.json index cda579e14fef..c10af975d939 100644 --- a/packages/osd-pm/package.json +++ b/packages/osd-pm/package.json @@ -42,7 +42,7 @@ "cmd-shim": "^2.1.0", "cpy": "^8.0.0", "dedent": "^0.7.0", - "del": "^5.1.0", + "del": "^6.1.1", "execa": "^4.0.2", "getopts": "^2.2.5", "glob": "^7.1.7", diff --git a/packages/osd-test/package.json b/packages/osd-test/package.json index 4016e4dcc05c..7776afc1de58 100644 --- a/packages/osd-test/package.json +++ b/packages/osd-test/package.json @@ -27,7 +27,7 @@ "dependencies": { "chalk": "^4.1.0", "dedent": "^0.7.0", - "del": "^5.1.0", + "del": "^6.1.1", "exit-hook": "^2.2.0", "getopts": "^2.2.5", "glob": "^7.1.7", diff --git a/packages/osd-ui-shared-deps/package.json b/packages/osd-ui-shared-deps/package.json index b75c4bd2a5c9..14cf480dba72 100644 --- a/packages/osd-ui-shared-deps/package.json +++ b/packages/osd-ui-shared-deps/package.json @@ -42,7 +42,7 @@ "@osd/dev-utils": "1.0.0", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "css-loader": "^5.2.7", - "del": "^5.1.0", + "del": "^6.1.1", "loader-utils": "^1.2.3", "val-loader": "^2.1.2", "webpack": "^4.41.5" diff --git a/yarn.lock b/yarn.lock index e3d69def9d6b..822684d097bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7059,6 +7059,20 @@ del@^6.0.0: rimraf "^3.0.2" slash "^3.0.0" +del@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" + integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg== + dependencies: + globby "^11.0.1" + graceful-fs "^4.2.4" + is-glob "^4.0.1" + is-path-cwd "^2.2.0" + is-path-inside "^3.0.2" + p-map "^4.0.0" + rimraf "^3.0.2" + slash "^3.0.0" + delaunator@5: version "5.0.0" resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.0.tgz#60f052b28bd91c9b4566850ebf7756efe821d81b"